[BACK]Return to disksubr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / sun

Annotation of src/sys/dev/sun/disksubr.c, Revision 1.14

1.14    ! martin      1: /*     $NetBSD: disksubr.c,v 1.13 2010/03/16 14:53:08 martin Exp $ */
1.1       bouyer      2:
1.4       perry       3: /*
1.1       bouyer      4:  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. Neither the name of the University nor the names of its contributors
                     16:  *    may be used to endorse or promote products derived from this software
                     17:  *    without specific prior written permission.
                     18:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     28:  * SUCH DAMAGE.
                     29:  */
                     30:
                     31: /*
                     32:  * Copyright (c) 1994, 1995 Gordon W. Ross
                     33:  * Copyright (c) 1994 Theo de Raadt
                     34:  * All rights reserved.
                     35:  *
                     36:  * Redistribution and use in source and binary forms, with or without
                     37:  * modification, are permitted provided that the following conditions
                     38:  * are met:
                     39:  * 1. Redistributions of source code must retain the above copyright
                     40:  *    notice, this list of conditions and the following disclaimer.
                     41:  * 2. Redistributions in binary form must reproduce the above copyright
                     42:  *    notice, this list of conditions and the following disclaimer in the
                     43:  *    documentation and/or other materials provided with the distribution.
                     44:  *
                     45:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     46:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     47:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     48:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     49:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     50:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     51:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     52:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     53:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     54:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     55:  */
                     56:
                     57: #include <sys/cdefs.h>
1.14    ! martin     58: __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.13 2010/03/16 14:53:08 martin Exp $");
1.1       bouyer     59:
                     60: #include <sys/param.h>
                     61: #include <sys/systm.h>
                     62: #include <sys/buf.h>
                     63: #include <sys/ioccom.h>
                     64: #include <sys/device.h>
                     65: #include <sys/disklabel.h>
                     66: #include <sys/disk.h>
                     67: #include <sys/dkbad.h>
                     68:
                     69: #include <dev/sun/disklabel.h>
                     70:
                     71: #if LABELSECTOR != 0
                     72: #error  "Default value of LABELSECTOR no longer zero?"
                     73: #endif
                     74:
1.6       christos   75: static const char *disklabel_sun_to_bsd(char *, struct disklabel *);
1.3       perry      76: static int disklabel_bsd_to_sun(struct disklabel *, char *);
1.1       bouyer     77:
                     78: /*
                     79:  * Attempt to read a disk label from a device
                     80:  * using the indicated strategy routine.
                     81:  * The label must be partly set up before this:
                     82:  * secpercyl, secsize and anything required for a block i/o read
                     83:  * operation in the driver's strategy/start routines
                     84:  * must be filled in before calling us.
                     85:  *
                     86:  * Return buffer for use in signalling errors if requested.
                     87:  *
                     88:  * Returns null on success and an error string on failure.
                     89:  */
                     90: const char *
1.12      dsl        91: readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp)
1.1       bouyer     92: {
                     93:        struct buf *bp;
                     94:        struct disklabel *dlp;
                     95:        struct sun_disklabel *slp;
                     96:        int error;
                     97:
                     98:        /* minimal requirements for archtypal disk label */
                     99:        if (lp->d_secperunit == 0)
                    100:                lp->d_secperunit = 0x1fffffff;
                    101:        if (lp->d_npartitions == 0) {
                    102:                lp->d_npartitions = RAW_PART + 1;
                    103:                if (lp->d_partitions[RAW_PART].p_size == 0)
                    104:                        lp->d_partitions[RAW_PART].p_size = 0x1fffffff;
                    105:                lp->d_partitions[RAW_PART].p_offset = 0;
                    106:        }
                    107:
                    108:        /* obtain buffer to probe drive with */
                    109:        bp = geteblk((int)lp->d_secsize);
                    110:
                    111:        /* next, dig out disk label */
                    112:        bp->b_dev = dev;
                    113:        bp->b_blkno = LABELSECTOR;
                    114:        bp->b_cylinder = 0;
                    115:        bp->b_bcount = lp->d_secsize;
                    116:        bp->b_flags |= B_READ;
                    117:        (*strat)(bp);
                    118:
                    119:        /* if successful, locate disk label within block and validate */
                    120:        error = biowait(bp);
                    121:        if (error == 0) {
                    122:                /* Save the whole block in case it has info we need. */
                    123:                memcpy(clp->cd_block, bp->b_data, sizeof(clp->cd_block));
                    124:        }
1.9       ad        125:        brelse(bp, 0);
1.1       bouyer    126:        if (error)
                    127:                return ("disk label read error");
                    128:
                    129:        /* Check for a NetBSD disk label at LABELOFFSET */
                    130:        dlp = (struct disklabel *) (clp->cd_block + LABELOFFSET);
                    131:        if (dlp->d_magic == DISKMAGIC) {
                    132:                if (dkcksum(dlp))
                    133:                        return ("NetBSD disk label corrupted");
                    134:                *lp = *dlp;
                    135:                return (NULL);
                    136:        }
                    137:
                    138:        /* Check for a Sun disk label (for PROM compatibility). */
                    139:        slp = (struct sun_disklabel *) clp->cd_block;
                    140:        if (slp->sl_magic == SUN_DKMAGIC)
                    141:                return (disklabel_sun_to_bsd(clp->cd_block, lp));
                    142:
                    143:        /*
                    144:         * Check for a NetBSD disk label somewhere in LABELSECTOR
                    145:         * (compat with others big-endian boxes)
                    146:         */
                    147:        for (dlp = (struct disklabel *)clp->cd_block;
                    148:            dlp <= (struct disklabel *)((char *)clp->cd_block +
                    149:            DEV_BSIZE - sizeof(*dlp));
                    150:            dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
                    151:                if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
                    152:                        continue;
                    153:                }
                    154:                if (dlp->d_npartitions > MAXPARTITIONS || dkcksum(dlp) != 0)
                    155:                        return("NetBSD disk label corrupted");
                    156:                else {
                    157:                        *lp = *dlp;
                    158:                        return(NULL);
                    159:                }
                    160:        }
                    161:
                    162:        memset(clp->cd_block, 0, sizeof(clp->cd_block));
                    163:        return ("no disk label");
                    164: }
                    165:
                    166: /*
                    167:  * Check new disk label for sensibility
                    168:  * before setting it.
                    169:  */
                    170: int
1.11      dsl       171: setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask, struct cpu_disklabel *clp)
1.1       bouyer    172: {
                    173:        int i;
                    174:        struct partition *opp, *npp;
                    175:
                    176:        /* sanity clause */
                    177:        if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 ||
                    178:            (nlp->d_secsize % DEV_BSIZE) != 0)
                    179:                return(EINVAL);
                    180:
                    181:        /* special case to allow disklabel to be invalidated */
                    182:        if (nlp->d_magic == 0xffffffff) {
                    183:                *olp = *nlp;
                    184:                return (0);
                    185:        }
                    186:
                    187:        if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
                    188:            dkcksum(nlp) != 0)
                    189:                return (EINVAL);
                    190:
                    191:        while ((i = ffs(openmask)) != 0) {
                    192:                i--;
                    193:                openmask &= ~(1 << i);
                    194:                if (nlp->d_npartitions <= i)
                    195:                        return (EBUSY);
                    196:                opp = &olp->d_partitions[i];
                    197:                npp = &nlp->d_partitions[i];
                    198:                if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
                    199:                        return (EBUSY);
                    200:        }
                    201:
                    202:        *olp = *nlp;
                    203:        return (0);
                    204: }
                    205:
                    206: /*
                    207:  * Write disk label back to device after modification.
                    208:  * Current label is already in clp->cd_block[]
                    209:  */
                    210: int
1.12      dsl       211: writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp)
1.1       bouyer    212: {
                    213:        struct buf *bp;
                    214:        int error;
                    215:        struct disklabel *dlp;
                    216:        struct sun_disklabel *slp;
                    217:
                    218:        /*
                    219:         * Embed native label in a piece of wasteland.
                    220:         */
                    221:        if (sizeof(struct disklabel) > sizeof slp->sl_bsdlabel)
                    222:                return EFBIG;
                    223:
                    224:        slp = (struct sun_disklabel *)clp->cd_block;
                    225:        memset(slp->sl_bsdlabel, 0, sizeof(slp->sl_bsdlabel));
                    226:        dlp = (struct disklabel *)slp->sl_bsdlabel;
                    227:        *dlp = *lp;
                    228:
                    229:        /* Build a SunOS compatible label around the native label */
                    230:        error = disklabel_bsd_to_sun(lp, clp->cd_block);
                    231:        if (error)
                    232:                return (error);
                    233:
                    234:        /* Get a buffer and copy the new label into it. */
                    235:        bp = geteblk((int)lp->d_secsize);
                    236:        memcpy(bp->b_data, clp->cd_block, sizeof(clp->cd_block));
                    237:
                    238:        /* Write out the updated label. */
                    239:        bp->b_dev = dev;
                    240:        bp->b_blkno = LABELSECTOR;
                    241:        bp->b_cylinder = 0;
                    242:        bp->b_bcount = lp->d_secsize;
                    243:        bp->b_flags |= B_WRITE;
                    244:        (*strat)(bp);
                    245:        error = biowait(bp);
1.9       ad        246:        brelse(bp, 0);
1.1       bouyer    247:
                    248:        return (error);
                    249: }
                    250:
                    251: /************************************************************************
                    252:  *
                    253:  * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c
                    254:  * and then substantially rewritten by Gordon W. Ross
                    255:  *
                    256:  ************************************************************************/
                    257:
                    258: /* What partition types to assume for Sun disklabels: */
                    259: static u_char
                    260: sun_fstypes[8] = {
                    261:        FS_BSDFFS,      /* a */
                    262:        FS_SWAP,        /* b */
                    263:        FS_OTHER,       /* c - whole disk */
                    264:        FS_BSDFFS,      /* d */
                    265:        FS_BSDFFS,      /* e */
                    266:        FS_BSDFFS,      /* f */
                    267:        FS_BSDFFS,      /* g */
                    268:        FS_BSDFFS,      /* h */
                    269: };
                    270:
                    271: /*
                    272:  * Given a SunOS disk label, set lp to a BSD disk label.
                    273:  * Returns NULL on success, else an error string.
                    274:  *
                    275:  * The BSD label is cleared out before this is called.
                    276:  */
1.5       christos  277: static const char *
1.10      dsl       278: disklabel_sun_to_bsd(char *cp, struct disklabel *lp)
1.1       bouyer    279: {
                    280:        struct sun_disklabel *sl;
                    281:        struct partition *npp;
                    282:        struct sun_dkpart *spp;
                    283:        int i, secpercyl;
1.14    ! martin    284:        unsigned int secpblck;
1.1       bouyer    285:        u_short cksum, *sp1, *sp2;
                    286:
                    287:        sl = (struct sun_disklabel *)cp;
                    288:
                    289:        /* Verify the XOR check. */
                    290:        sp1 = (u_short *)sl;
                    291:        sp2 = (u_short *)(sl + 1);
                    292:        cksum = 0;
                    293:        while (sp1 < sp2)
                    294:                cksum ^= *sp1++;
                    295:        if (cksum != 0)
                    296:                return("SunOS disk label, bad checksum");
                    297:
                    298:        /* Format conversion. */
                    299:        lp->d_magic = DISKMAGIC;
                    300:        lp->d_magic2 = DISKMAGIC;
                    301:        memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname));
                    302:
1.14    ! martin    303:        secpblck = lp->d_secsize / 512;
        !           304:        if (secpblck == 0) secpblck = 1; /* can't happen */
1.1       bouyer    305:        lp->d_secsize = 512;
                    306:        lp->d_nsectors   = sl->sl_nsectors;
                    307:        lp->d_ntracks    = sl->sl_ntracks;
                    308:        lp->d_ncylinders = sl->sl_ncylinders;
                    309:
                    310:        secpercyl = sl->sl_nsectors * sl->sl_ntracks;
                    311:        lp->d_secpercyl  = secpercyl;
                    312:        lp->d_secperunit = secpercyl * sl->sl_ncylinders;
                    313:
                    314:        lp->d_sparespercyl = sl->sl_sparespercyl;
                    315:        lp->d_acylinders   = sl->sl_acylinders;
                    316:        lp->d_rpm          = sl->sl_rpm;
                    317:        lp->d_interleave   = sl->sl_interleave;
                    318:
                    319:        lp->d_npartitions = 8;
                    320:        /* These are as defined in <ufs/ffs/fs.h> */
                    321:        lp->d_bbsize = 8192;    /* XXX */
                    322:        lp->d_sbsize = 8192;    /* XXX */
                    323:
                    324:        for (i = 0; i < 8; i++) {
                    325:                spp = &sl->sl_part[i];
                    326:                npp = &lp->d_partitions[i];
1.14    ! martin    327:
1.13      martin    328:                if (npp->p_fstype == FS_ISO9660
1.14    ! martin    329:                    && spp->sdkp_cyloffset * secpercyl == npp->p_offset*secpblck
        !           330:                    && spp->sdkp_nsectors <= npp->p_size*secpblck
1.13      martin    331:                    && npp->p_size > 0 && spp->sdkp_nsectors > 0) {
                    332:                        /*
                    333:                         * This happens for example on sunlabel'd hybrid
                    334:                         * (ffs + ISO9660) CDs, like our install CDs.
                    335:                         * The cd driver has initialized a valid ISO9660
                    336:                         * partition (including session parameters), so
                    337:                         * we better not overwrite it.
                    338:                         */
1.14    ! martin    339:                        npp->p_offset *= secpblck;
        !           340:                        npp->p_size = spp->sdkp_nsectors;
        !           341:                        npp->p_cdsession *= secpblck;
1.13      martin    342:                        continue;
                    343:                }
1.1       bouyer    344:                npp->p_offset = spp->sdkp_cyloffset * secpercyl;
                    345:                npp->p_size = spp->sdkp_nsectors;
                    346:                if (npp->p_size == 0) {
                    347:                        npp->p_fstype = FS_UNUSED;
                    348:                } else {
                    349:                        npp->p_fstype = sun_fstypes[i];
                    350:                        if (npp->p_fstype == FS_BSDFFS) {
                    351:                                /*
                    352:                                 * The sun label does not store the FFS fields,
                    353:                                 * so just set them with default values here.
                    354:                                 */
                    355:                                npp->p_fsize = 1024;
                    356:                                npp->p_frag = 8;
                    357:                                npp->p_cpg = 16;
                    358:                        }
                    359:                }
                    360:        }
                    361:
                    362:        lp->d_checksum = 0;
                    363:        lp->d_checksum = dkcksum(lp);
                    364:        return (NULL);
                    365: }
                    366:
                    367: /*
                    368:  * Given a BSD disk label, update the Sun disklabel
                    369:  * pointed to by cp with the new info.  Note that the
                    370:  * Sun disklabel may have other info we need to keep.
                    371:  * Returns zero or error code.
                    372:  */
                    373: static int
1.10      dsl       374: disklabel_bsd_to_sun(struct disklabel *lp, char *cp)
1.1       bouyer    375: {
                    376:        struct sun_disklabel *sl;
                    377:        struct partition *npp;
                    378:        struct sun_dkpart *spp;
                    379:        int i, secpercyl;
                    380:        u_short cksum, *sp1, *sp2;
                    381:
                    382:        if (lp->d_secsize != 512)
                    383:                return (EINVAL);
                    384:
                    385:        sl = (struct sun_disklabel *)cp;
                    386:
                    387:        /*
                    388:         * Format conversion.
                    389:         */
                    390:        memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
                    391:        sl->sl_rpm = lp->d_rpm;
                    392:        sl->sl_pcylinders   = lp->d_ncylinders + lp->d_acylinders; /* XXX */
                    393:        sl->sl_sparespercyl = lp->d_sparespercyl;
                    394:        sl->sl_interleave   = lp->d_interleave;
                    395:        sl->sl_ncylinders   = lp->d_ncylinders;
                    396:        sl->sl_acylinders   = lp->d_acylinders;
                    397:        sl->sl_ntracks      = lp->d_ntracks;
                    398:        sl->sl_nsectors     = lp->d_nsectors;
                    399:
                    400:        secpercyl = sl->sl_nsectors * sl->sl_ntracks;
                    401:        for (i = 0; i < 8; i++) {
                    402:                spp = &sl->sl_part[i];
                    403:                npp = &lp->d_partitions[i];
                    404:
                    405:                /*
                    406:                 * SunOS partitions must start on a cylinder boundary.
                    407:                 * Note this restriction is forced upon NetBSD/sparc
                    408:                 * labels too, since we want to keep both labels
                    409:                 * synchronised.
                    410:                 */
                    411:                if (npp->p_offset % secpercyl)
                    412:                        return (EINVAL);
                    413:                spp->sdkp_cyloffset = npp->p_offset / secpercyl;
                    414:                spp->sdkp_nsectors = npp->p_size;
                    415:        }
                    416:        sl->sl_magic = SUN_DKMAGIC;
                    417:
                    418:        /* Compute the XOR check. */
                    419:        sp1 = (u_short *)sl;
                    420:        sp2 = (u_short *)(sl + 1);
                    421:        sl->sl_cksum = cksum = 0;
                    422:        while (sp1 < sp2)
                    423:                cksum ^= *sp1++;
                    424:        sl->sl_cksum = cksum;
                    425:
                    426:        return (0);
                    427: }
                    428:
                    429: /*
                    430:  * Search the bad sector table looking for the specified sector.
                    431:  * Return index if found.
                    432:  * Return -1 if not found.
                    433:  */
                    434: int
1.11      dsl       435: isbad(struct dkbad *bt, int cyl, int trk, int sec)
1.1       bouyer    436: {
                    437:        int i;
                    438:        long blk, bblk;
                    439:
                    440:        blk = ((long)cyl << 16) + (trk << 8) + sec;
                    441:        for (i = 0; i < 126; i++) {
                    442:                bblk = ((long)bt->bt_bad[i].bt_cyl << 16) +
                    443:                        bt->bt_bad[i].bt_trksec;
                    444:                if (blk == bblk)
                    445:                        return (i);
                    446:                if (blk < bblk || bblk < 0)
                    447:                        break;
                    448:        }
                    449:        return (-1);
                    450: }

CVSweb <webmaster@jp.NetBSD.org>