root/sys/arch/mvme68k/mvme68k/disksubr.c
/*      $NetBSD: disksubr.c,v 1.36 2019/04/03 22:10:50 christos Exp $   */

/*
 * Copyright (c) 1995 Dale Rahn.
 * All rights reserved.
 *   
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.36 2019/04/03 22:10:50 christos Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
#define FSTYPENAMES
#include <sys/disklabel.h>
#include <sys/disk.h>

#include <dev/scsipi/scsi_all.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsiconf.h>

#include <machine/autoconf.h>

#ifdef DEBUG
int disksubr_debug = 0;
#endif

static void bsdtocpulabel(struct disklabel *lp, struct cpu_disklabel *clp);
static void cputobsdlabel(struct disklabel *lp, struct cpu_disklabel *clp);

#ifdef DEBUG
static void printlp(struct disklabel *lp, const char *str);
static void printclp(struct cpu_disklabel *clp, const char *str);
#endif


/*
 * Attempt to read a disk label from a device
 * using the indicated strategy routine.
 * The label must be partly set up before this:
 * secpercyl and anything required in the strategy routine
 * (e.g., sector size) must be filled in before calling us.
 * Returns null on success and an error string on failure.
 */
const char *
readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    struct cpu_disklabel *clp)
{
        struct buf *bp;
        const char *msg = NULL;

        /* obtain buffer to probe drive with */
        bp = geteblk((int)lp->d_secsize);

        /* request no partition relocation by driver on I/O operations */
        bp->b_dev = dev;
        bp->b_blkno = 0; /* contained in block 0 */
        bp->b_bcount = lp->d_secsize;
        bp->b_flags |= B_READ;
        bp->b_cylinder = 0; /* contained in block 0 */
        (*strat)(bp);

        if (biowait(bp)) {
                msg = "cpu_disklabel read error\n";
        } else {
                memcpy(clp, bp->b_data, sizeof (struct cpu_disklabel));
        }

        brelse(bp, 0);

        if (msg || clp->magic1 != DISKMAGIC || clp->magic2 != DISKMAGIC) {
                return msg; 
        }

        cputobsdlabel(lp, clp);
#ifdef DEBUG
        if(disksubr_debug > 0) {
                printlp(lp, "readdisklabel: bsd label");
                printclp(clp, "readdisklabel: cpu label");
        }
#endif
        return msg;
}

/*
 * Write disk label back to device after modification.
 */
int
writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    struct cpu_disklabel *clp)
{
        struct buf *bp;
        int error;

#ifdef DEBUG
        if(disksubr_debug > 0) {
                printlp(lp, "writedisklabel: bsd label");
        }
#endif

        /*
         * obtain buffer to read initial cpu_disklabel, for bootloader size :-)
         */
        bp = geteblk((int)lp->d_secsize);

        /* request no partition relocation by driver on I/O operations */
        bp->b_dev = dev;
        bp->b_blkno = 0; /* contained in block 0 */
        bp->b_bcount = lp->d_secsize;
        bp->b_flags |= B_READ;
        bp->b_cylinder = 0; /* contained in block 0 */
        (*strat)(bp);

        if ( (error = biowait(bp)) != 0 ) {
                /* nothing */
        } else {
                memcpy(clp, bp->b_data, sizeof(struct cpu_disklabel));
        }

        brelse(bp, 0);

        if (error) {
                return error;
        }

        bsdtocpulabel(lp, clp);

#ifdef DEBUG
        if (disksubr_debug > 0) {
                printclp(clp, "writedisklabel: cpu label");
        }
#endif

        if (lp->d_magic == DISKMAGIC && lp->d_magic2 == DISKMAGIC &&
            dkcksum(lp) == 0) {
                /* obtain buffer to scrozz drive with */
                bp = geteblk((int)lp->d_secsize);

                memcpy(bp->b_data, clp, sizeof(struct cpu_disklabel));

                /*
                 * request no partition relocation by driver on I/O operations
                 */
                bp->b_dev = dev;
                bp->b_blkno = 0; /* contained in block 0 */
                bp->b_bcount = lp->d_secsize;
                bp->b_flags |= B_WRITE;
                bp->b_cylinder = 0; /* contained in block 0 */
                (*strat)(bp);

                error = biowait(bp);

                brelse(bp, 0);
        }
        return error; 
}

static void
bsdtocpulabel(struct disklabel *lp, struct cpu_disklabel *clp)
{
        int i;

        clp->magic1 = lp->d_magic;
        clp->type = lp->d_type;
        clp->subtype = lp->d_subtype;
        strncpy(clp->vid_vd, lp->d_typename, 16);
        strncpy(clp->packname, lp->d_packname, 16);
        clp->cfg_psm = lp->d_secsize;
        clp->cfg_spt = lp->d_nsectors;
        clp->cfg_trk = lp->d_ncylinders;        /* trk is really num of cyl! */
        clp->cfg_hds = lp->d_ntracks;

        clp->secpercyl = lp->d_secpercyl;
        clp->secperunit = lp->d_secperunit;
        clp->sparespertrack = lp->d_sparespertrack;
        clp->sparespercyl = lp->d_sparespercyl;
        clp->acylinders = lp->d_acylinders;
        clp->rpm = lp->d_rpm;

        clp->cfg_ilv = lp->d_interleave;
        clp->cfg_sof = lp->d_trackskew;
        clp->cylskew = lp->d_cylskew;
        clp->headswitch = lp->d_headswitch;

        /* this silly table is for winchester drives */
        if (lp->d_trkseek < 6) {
                clp->cfg_ssr = 0;
        } else if (lp->d_trkseek < 10) {
                clp->cfg_ssr = 1;
        } else if (lp->d_trkseek < 15) {
                clp->cfg_ssr = 2;
        } else if (lp->d_trkseek < 20) {
                clp->cfg_ssr = 3;
        } else {
                clp->cfg_ssr = 4;
        }

        clp->flags = lp->d_flags;
        for (i = 0; i < NDDATA; i++)
                clp->drivedata[i] = lp->d_drivedata[i];
        for (i = 0; i < NSPARE; i++)
                clp->spare[i] = lp->d_spare[i];

        clp->magic2 = lp->d_magic2;
        clp->checksum = lp->d_checksum;
        clp->partitions = lp->d_npartitions;
        clp->bbsize = lp->d_bbsize;
        clp->sbsize = lp->d_sbsize;
        clp->checksum = lp->d_checksum;
        /* note: assume at least 4 partitions */
        memcpy(clp->vid_4, &lp->d_partitions[0], sizeof(struct partition) * 4);
        memset(clp->cfg_4, 0, sizeof(struct partition) * 12);
        memcpy(clp->cfg_4, &lp->d_partitions[4], sizeof(struct partition) 
            * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12));

        /*
         * here are the parts of the cpu_disklabel the kernel must init.
         * see disklabel.h for more details
         * [note: this used to be handled by 'wrtvid']
         */
        memcpy(clp->vid_id, VID_ID, sizeof(clp->vid_id));
        clp->vid_oss = VID_OSS;
        clp->vid_osl = VID_OSL;
        clp->vid_osa_u = VID_OSAU;
        clp->vid_osa_l = VID_OSAL;
        clp->vid_cas = VID_CAS;
        clp->vid_cal = VID_CAL;
        memcpy(clp->vid_mot, VID_MOT, sizeof(clp->vid_mot));
        clp->cfg_rec = CFG_REC;
        clp->cfg_psm = CFG_PSM;
}

static void
cputobsdlabel(struct disklabel *lp, struct cpu_disklabel *clp)
{
        int i;

        lp->d_magic = clp->magic1;
        lp->d_type = clp->type;
        lp->d_subtype = clp->subtype;
        strncpy(lp->d_typename, clp->vid_vd, 16);
        strncpy(lp->d_packname, clp->packname, 16);
        lp->d_secsize = clp->cfg_psm;
        lp->d_nsectors = clp->cfg_spt;
        lp->d_ncylinders = clp->cfg_trk; /* trk is really num of cyl! */
        lp->d_ntracks = clp->cfg_hds;

        lp->d_secpercyl = clp->secpercyl;
        lp->d_secperunit = clp->secperunit;
        lp->d_secpercyl = clp->secpercyl;
        lp->d_secperunit = clp->secperunit;
        lp->d_sparespertrack = clp->sparespertrack;
        lp->d_sparespercyl = clp->sparespercyl;
        lp->d_acylinders = clp->acylinders;
        lp->d_rpm = clp->rpm;
        lp->d_interleave = clp->cfg_ilv;
        lp->d_trackskew = clp->cfg_sof;
        lp->d_cylskew = clp->cylskew;
        lp->d_headswitch = clp->headswitch;

        /* this silly table is for winchester drives */
        switch (clp->cfg_ssr) {
        case 0:
                lp->d_trkseek = 0;
                break;
        case 1:
                lp->d_trkseek = 6;
                break;
        case 2:
                lp->d_trkseek = 10;
                break;
        case 3:
                lp->d_trkseek = 15;
                break;
        case 4:
                lp->d_trkseek = 20;
                break;
        default:
                lp->d_trkseek = 0;
        }
        lp->d_flags = clp->flags;
        for (i = 0; i < NDDATA; i++)
                lp->d_drivedata[i] = clp->drivedata[i];
        for (i = 0; i < NSPARE; i++)
                lp->d_spare[i] = clp->spare[i];

        lp->d_magic2 = clp->magic2;
        lp->d_checksum = clp->checksum;
        lp->d_npartitions = clp->partitions;
        lp->d_bbsize = clp->bbsize;
        lp->d_sbsize = clp->sbsize;
        /* note: assume at least 4 partitions */
        memcpy(&lp->d_partitions[0], clp->vid_4, sizeof(struct partition) * 4);
        memcpy(&lp->d_partitions[4], clp->cfg_4, sizeof(struct partition) 
            * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12));
        lp->d_checksum = 0;
        lp->d_checksum = dkcksum(lp);
#if DEBUG
        if (disksubr_debug > 0) {
                printlp(lp, "translated label read from disk\n");
        }
#endif
}

#ifdef DEBUG
static void
printlp(struct disklabel *lp, const char *str)
{
        int i;

        printf("%s\n", str);
        printf("magic1 %x\n", lp->d_magic);
        printf("magic2 %x\n", lp->d_magic2);
        printf("typename %s\n", lp->d_typename);
        printf("secsize %x nsect %x ntrack %x ncylinders %x\n",
            lp->d_secsize, lp->d_nsectors, lp->d_ntracks, lp->d_ncylinders);
        printf("Num partitions %x\n", lp->d_npartitions);
        for (i = 0; i < lp->d_npartitions; i++) {
                struct partition *part = &lp->d_partitions[i];
                const char *fstyp = fstypenames[part->p_fstype];
                
                printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n",
                    'a' + i, part->p_size, part->p_offset, fstyp,
                    part->p_frag, part->p_cpg);
        }
}

static void
printclp(struct cpu_disklabel *clp, const char *str)
{
        int maxp, i;

        printf("%s\n", str);
        printf("magic1 %lx\n", clp->magic1);
        printf("magic2 %lx\n", clp->magic2);
        printf("typename %s\n", clp->vid_vd);
        printf("secsize %x nsect %x ntrack %x ncylinders %x\n",
            clp->cfg_psm, clp->cfg_spt, clp->cfg_hds, clp->cfg_trk);
        printf("Num partitions %x\n", clp->partitions);
        maxp = clp->partitions < 16 ? clp->partitions : 16;
        for (i = 0; i < maxp; i++) {
                struct partition *part;
                const char *fstyp;

                if (i < 4) {
                        part = (void *)&clp->vid_4[0];
                        part = &part[i];
                } else {
                        part = (void *)&clp->cfg_4[0];
                        part = &part[i-4];
                }

                fstyp = fstypenames[part->p_fstype];
                
                printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n",
                    'a' + i, part->p_size, part->p_offset, fstyp,
                    part->p_frag, part->p_cpg);
        }
}
#endif