root/sys/arch/ews4800mips/ews4800mips/disklabel_conv.c
/*      $NetBSD: disklabel_conv.c,v 1.4 2008/04/28 20:23:18 martin Exp $        */

/*-
 * Copyright (c) 2004 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by UCHIYAMA Yasushi.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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: disklabel_conv.c,v 1.4 2008/04/28 20:23:18 martin Exp $");

#include <sys/systm.h>
#include <sys/param.h>

#ifndef _KERNEL
#include "local.h"
#endif

#include <sys/disklabel.h>

/*
 * NetBSD/ews4800mips EWS-UX compatible disk layout.
 *
 * 0============================+ cylinder 0
 * 1    1stboot program (4KB)   |
 * .                            .
 * 7----------------------------+
 * 8    PDINFO                  | UX unvisible region.
 * 9    BSD disklabel           | I (uch) decided to locate disklabel here.
 * .                            .
 * .    error log       (UX)    |
 * +============================+ cylinder 1
 * |    logical_start   (UX)    |
 * |    VTOC                    |
 * .                            . UX Boot block (partition 7)
 * .                            . 100 blocks (default. at least 2 blocks)
 * .                            .
 * .                            .
 * +============================+
 * |   BFS                      |
 * |            boot loader     |
 * .            disklabel       .
 * .            and etc.        . BFS           (partition 3)
 * .                            .
 * .                            .
 * .                            .
 * -----------------------------+
 */

#define _BFS_SIZE                       16384   /* 8MB */
#define _BOOTBLOCK_SIZE                 100     /* UX default */
#define _FAKE_TRACKS_PER_CYLINDER       16
#define _FAKE_SECTORS_PER_TRACK         1

void
disklabel_set_default(struct disklabel *d)
{

        d->d_magic = DISKMAGIC;
        d->d_magic2 = DISKMAGIC;
        d->d_secsize = DEV_BSIZE;
        d->d_npartitions = MAXPARTITIONS;
}

void
vtoc_set_default( struct cpu_disklabel *ux, struct disklabel *d)
{
        struct pdinfo_sector *pdinfo = &ux->pdinfo;
        struct vtoc_sector *vtoc = &ux->vtoc;
        struct ux_partition *bfs;
        struct ux_partition *boot;
        struct ux_partition *bsdraw;
        int nsectors, logical_sector, cylinder_blocks, res;

        memset(vtoc, 0, sizeof *vtoc);
        memset(pdinfo, 0, sizeof *pdinfo);
        if (d)
                cylinder_blocks = d->d_ntracks * d->d_nsectors;
        else
                cylinder_blocks =
                    _FAKE_TRACKS_PER_CYLINDER * _FAKE_SECTORS_PER_TRACK;
        logical_sector = cylinder_blocks;

        pdinfo->drive_id = 0x5c512000;  /* Fake for EWS-UX */
        pdinfo->magic = PDINFO_MAGIC;
        pdinfo->version = PDINFO_VERSION;
        pdinfo->logical_sector = logical_sector;
        pdinfo->ux.errorlog_sector = logical_sector - 1;
        pdinfo->ux.errorlog_size_byte = DEV_BSIZE;

        if (d) { /* use drivers disk geometory */
                pdinfo->geometory.cylinders_per_drive = d->d_ncylinders;
                pdinfo->geometory.tracks_per_cylinder = d->d_ntracks;
                pdinfo->geometory.sectors_per_track = d->d_nsectors;
                pdinfo->geometory.bytes_per_sector = d->d_secsize;
                nsectors = d->d_ncylinders * d->d_ntracks * d->d_nsectors;
        } else { /* set fake */
                pdinfo->geometory.sectors_per_track =
                    _FAKE_SECTORS_PER_TRACK;
                pdinfo->geometory.tracks_per_cylinder =
                    _FAKE_TRACKS_PER_CYLINDER;
                pdinfo->geometory.cylinders_per_drive = 0x1fffffff;
                pdinfo->geometory.bytes_per_sector = DEV_BSIZE;
                nsectors = 0x1fffffff;
        }

        /* following magic numbers are required for EWS-UX */
        pdinfo->device_depend[15] = 0xfb7e10;
        pdinfo->device_depend[16] = 0x200;
        pdinfo->device_depend[17] = 0x10;

        vtoc->magic = VTOC_MAGIC;
        vtoc->version = VTOC_VERSION;
        vtoc->sector_size_byte = DEV_BSIZE;
        vtoc->npartitions = VTOC_MAXPARTITIONS;

        boot = &vtoc->partition[7];
        boot->tag = VTOC_TAG_BOOT;
        boot->flags = VTOC_FLAG_UNMOUNT;
        boot->start_sector = 0;
        boot->nsectors = _BOOTBLOCK_SIZE;

        bfs = &vtoc->partition[3];
        bfs->tag = VTOC_TAG_STAND;
        bfs->flags = 0;
        bfs->start_sector = _BOOTBLOCK_SIZE;

        res = nsectors - bfs->start_sector;
        bfs->nsectors = res > _BFS_SIZE ? _BFS_SIZE : res;

        bsdraw = &vtoc->partition[RAW_PART];
        bsdraw->tag = VTOC_TAG_NONAME;
        bsdraw->flags = VTOC_FLAG_UNMOUNT;
        bsdraw->start_sector = -pdinfo->logical_sector;
        bsdraw->nsectors = nsectors;
}

void
disklabel_to_vtoc(struct cpu_disklabel *ux, struct disklabel *d)
{
        struct pdinfo_sector *pdinfo = &ux->pdinfo;
        struct vtoc_sector *vtoc = &ux->vtoc;
        struct ux_partition *up;
        struct partition *p;
        uint32_t offset = pdinfo->logical_sector;
        int i;

        pdinfo->geometory.cylinders_per_drive = d->d_ncylinders;
        pdinfo->geometory.tracks_per_cylinder = d->d_ntracks;
        pdinfo->geometory.sectors_per_track = d->d_nsectors;
        pdinfo->geometory.bytes_per_sector = d->d_secsize;

        vtoc->npartitions = d->d_npartitions;
        vtoc->sector_size_byte = d->d_secsize;

        up = vtoc->partition;
        p = d->d_partitions;
        for (i = 0; i < vtoc->npartitions; i++, up++, p++) {
                if ((up->nsectors = p->p_size) != 0)
                        up->start_sector = p->p_offset - offset;
                else
                        up->start_sector = 0;

                switch (p->p_fstype) {
                case FS_BOOT:
                        up->tag = VTOC_TAG_BOOT;
                        up->flags = VTOC_FLAG_UNMOUNT;
                        break;
                case FS_SYSVBFS:
                        up->tag = VTOC_TAG_STAND;
                        break;
                case FS_SWAP:
                        up->tag = VTOC_TAG_SWAP;
                        up->flags = VTOC_FLAG_UNMOUNT;
                        break;
                case FS_BSDFFS:
                        up->tag = __VTOC_TAG_BSDFFS;
                        break;
                case FS_UNUSED:
                        if (i != RAW_PART && p->p_size > 0) {
                                up->tag = VTOC_TAG_RAWDISK;
                                up->flags = VTOC_FLAG_UNMOUNT;
                        }
                        break;
                default:
                        break;
                }
        }
}

void
vtoc_to_disklabel(struct cpu_disklabel *ux, struct disklabel *d)
{
        struct pdinfo_sector *pdinfo = &ux->pdinfo;
        struct vtoc_sector *vtoc = &ux->vtoc;
        struct ux_partition *up;
        struct partition *p;
        uint32_t offset = pdinfo->logical_sector;
        int i;

        d->d_secsize = pdinfo->geometory.bytes_per_sector;
        d->d_nsectors = pdinfo->geometory.sectors_per_track;
        d->d_ntracks = pdinfo->geometory.tracks_per_cylinder;
        d->d_ncylinders = pdinfo->geometory.cylinders_per_drive;
        d->d_secpercyl = d->d_nsectors * d->d_ntracks;
        d->d_secperunit = d->d_ncylinders * d->d_secpercyl;

        d->d_npartitions = vtoc->npartitions;
        d->d_secsize = vtoc->sector_size_byte;

        up = vtoc->partition;
        p = d->d_partitions;
        for (i = 0; i < vtoc->npartitions; i++, up++, p++) {

                if ((p->p_size = up->nsectors) != 0)
                        p->p_offset = up->start_sector + offset;
                else
                        p->p_offset = 0;

                switch (up->tag) {
                case VTOC_TAG_BOOT:
                        p->p_fstype = FS_BOOT;
                        break;
                case VTOC_TAG_STAND:
                        p->p_fstype = FS_SYSVBFS;
                        break;
                case VTOC_TAG_RAWDISK:
                        p->p_fstype = FS_UNUSED;
                        break;
                case VTOC_TAG_SWAP:
                        p->p_fstype = FS_SWAP;
                        break;
                case VTOC_TAG_NONAME:
                case VTOC_TAG_ROOT:
                case VTOC_TAG_USR:
                case VTOC_TAG_VAR:
                case VTOC_TAG_HOME:
                        p->p_fstype = FS_SYSV;
                        break;
                default:
                        if (up->nsectors != 0)
                                p->p_fstype = FS_SYSV;
                        else
                                p->p_fstype = FS_UNUSED;
                        break;
                }
        }

        d->d_checksum = 0;
        d->d_checksum = dkcksum(d);
}

bool
disklabel_sanity(struct disklabel *d)
{

        if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC ||
            dkcksum(d) != 0)
                return false;

        return true;
}