root/sys/arch/mipsco/stand/common/saio.c
/*      $NetBSD: saio.c,v 1.15 2021/07/24 21:31:34 andvar Exp $ */

/*
 * Copyright (c) 1992, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Van Jacobson of Lawrence Berkeley Laboratory and Ralph Campbell.
 *
 * 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. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
 *
 *      @(#)rz.c        8.1 (Berkeley) 6/10/93
 */

#include <lib/libsa/stand.h>
#include <lib/libkern/libkern.h>
#include <machine/prom.h>

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

#include "common.h"
#include "saio.h"

struct  saio_softc {
        int     sc_fd;                  /* PROM file id */
        int     sc_ctlr;                /* controller number */
        int     sc_unit;                /* disk unit number */
        int     sc_part;                /* disk partition number */
        struct  disklabel sc_label;     /* disk label for this disk */
};

struct io_arg {
        int retval;
        unsigned long sectst;
        unsigned long memaddr;
        unsigned long datasz;
};

#define IOB_BUFSZ       512
#define IOB_INODESZ     316

struct device_table {
        char *dt_string;        /* device name */
        int (*dt_init) (int);   /* device init routine */
        int (*dt_open)(int);    /* device open routine */
        int (*dt_strategy)(int);        /* device strategy routine, returns cnt */
        int (*dt_close)(int);   /* device close routine */
        int (*dt_ioctl)(int);   /* device ioctl routine */
        int dt_type;            /* device "type" */
        int dt_fs;              /* file system type */
        char *dt_desc;          /* device description */
};

struct sa_iob {
        char    i_buf[IOB_BUFSZ];       /* file system or tape header */
        char    i_ino_dir[IOB_INODESZ]; /* inode or disk/tape directory */

        int     i_flgs;         /* see F_ below */
        int     i_ctlr;         /* controller board */
        int     i_unit;         /* pseudo device unit */
        int     i_part;         /* disk partition */
        char    *i_ma;          /* memory address of i/o buffer */
        int     i_cc;           /* character count of transfer */
        int32_t i_offset;       /* seek offset in file */
        /* XXX ondisk32 */
        int32_t i_bn;           /* 1st block # of next read */
        int     i_fstype;       /* file system type */
        int     i_errno;        /* error # return */
        unsigned int    i_devaddr;      /* csr address */
        struct device_table *i_dp;      /* pointer into device_table */
        char    *i_bufp;                        /* i/o buffer for blk devs */
}__attribute__((__packed__));

extern struct sa_iob *saiob[];

int
saiostrategy(void *devdata, int rw, daddr_t bn, size_t reqcnt, void *addr, size_t *cnt)
        /* cnt:  out: number of bytes transferred */
{
        struct saio_softc *sc = (struct saio_softc *)devdata;
        int part = sc->sc_part;
        struct partition *pp = &sc->sc_label.d_partitions[part];
        int s;
        long offset;
        struct sa_iob *iob;
        char *adr;

        offset = bn * DEV_BSIZE;
        *cnt = 0;

        /*
         * Partial-block transfers not handled.
         */
        if (reqcnt & (DEV_BSIZE - 1)) {
                return (EINVAL);
        }
        offset += pp->p_offset * DEV_BSIZE;

        iob = saiob[sc->sc_fd];
        iob->i_offset = offset;

#if notyet
        if (prom_lseek(sc->sc_fd, offset, 0) < 0)
                return (EIO);
#endif

        adr = (char *)addr;
        while (*cnt < reqcnt) {
                s = prom_read(sc->sc_fd, iob->i_buf, 512);
                if (s < 0) {
                        return (EIO);
                }
                memcpy(adr, iob->i_buf, s);
                *cnt += s;
                adr += s;
        }
        return (0);
}

int
saioopen(struct open_file *f, ...)
{
        int ctlr, unit, part;

        struct saio_softc *sc;
        struct disklabel *lp;
        int i;
        char *msg;
        char buf[DEV_BSIZE];
        size_t cnt;
        static char device[] = "dksd(0,0,10)";

        va_list ap;

        va_start(ap, f);

        ctlr = va_arg(ap, int);
        unit = va_arg(ap, int);
        part = va_arg(ap, int);

        va_end(ap);

        device[5] = '0' + ctlr;
        device[7] = '0' + unit;

        i = prom_open(device, 0);
        if (i < 0) {
                printf("open failed\n");
                return (ENXIO);
        }

        sc = alloc(sizeof(struct saio_softc));
        memset(sc, 0, sizeof(struct saio_softc));
        f->f_devdata = (void *)sc;

        sc->sc_fd = i;
        sc->sc_ctlr = ctlr;
        sc->sc_unit = unit;
        sc->sc_part = part;

        /* try to read disk label and partition table information */
        lp = &sc->sc_label;
        lp->d_secsize = DEV_BSIZE;
        lp->d_secpercyl = 1;
        lp->d_npartitions = MAXPARTITIONS;
        lp->d_partitions[part].p_offset = 0;
        lp->d_partitions[part].p_size = 0x7fffffff;

        i = saiostrategy(sc, F_READ, (daddr_t)LABELSECTOR, DEV_BSIZE, buf, &cnt);
        if (i || cnt != DEV_BSIZE) {
                printf("%s: error reading disk label\n", device);
                goto bad;
        }

        msg = getdisklabel(buf, lp);
        if (msg) {
#ifdef LIBSA_NO_DISKLABEL_MSGS
                printf("%s: no disklabel\n", device);
#else
                printf("getlabel: %s\n", msg);
#endif
                return (0);
        }
        if (part >= lp->d_npartitions || lp->d_partitions[part].p_size == 0) {
        bad:
                dealloc(sc, sizeof(struct saio_softc));
                return (ENXIO);
        }
        return (0);
}

#ifndef LIBSA_NO_DEV_CLOSE
int
saioclose(struct open_file *f)
{

        prom_close(((struct saio_softc *)f->f_devdata)->sc_fd);
        dealloc(f->f_devdata, sizeof(struct saio_softc));
        f->f_devdata = (void *)0;
        return (0);
}
#endif