#include "libsa.h"
#include <sys/param.h>
#include <sys/disklabel.h>
#include <machine/rpb.h>
#include <machine/prom.h>
struct disk_softc {
int sc_fd;
int sc_part;
struct disklabel sc_label;
};
int
diskstrategy(void *devdata, int rw, daddr_t bn, size_t reqcnt, void *addrvoid,
size_t *cnt)
{
char *addr = addrvoid;
struct disk_softc *sc;
struct partition *pp;
prom_return_t ret;
int s;
#ifdef DEBUG
if ((reqcnt & 0xffffff) != reqcnt || reqcnt == 0)
asm("call_pal 0");
#endif
twiddle();
if (reqcnt & (DEV_BSIZE - 1)) {
*cnt = 0;
return (EINVAL);
}
sc = (struct disk_softc *)devdata;
pp = &sc->sc_label.d_partitions[sc->sc_part];
bn += DL_GETPOFFSET(pp);
if (rw == F_READ)
ret.bits = prom_read(sc->sc_fd, reqcnt, addr, bn);
else
ret.bits = prom_write(sc->sc_fd, reqcnt, addr, bn);
if (ret.u.status)
return (EIO);
if (cnt)
*cnt = ret.u.retval;
return (0);
}
int
diskopen(struct open_file *f, ...)
{
struct disklabel *lp;
prom_return_t ret;
size_t cnt, devlen;
int i;
char *msg, buf[DEV_BSIZE];
struct disk_softc *sc;
va_list ap;
unsigned int part = 0;
char devname[128];
ret.bits = prom_getenv(PROM_E_BOOTED_DEV, devname, sizeof(devname));
devlen = ret.u.retval;
ret.bits = prom_open((u_int64_t)devname, devlen);
if (ret.u.status == 2)
return (ENXIO);
if (ret.u.status == 3)
return (EIO);
sc = alloc(sizeof(struct disk_softc));
bzero(sc, sizeof(struct disk_softc));
f->f_devdata = (void *)sc;
sc->sc_fd = ret.u.retval;
sc->sc_part = part;
lp = &sc->sc_label;
lp->d_secsize = DEV_BSIZE;
lp->d_secpercyl = 1;
lp->d_npartitions = MAXPARTITIONS;
DL_SETPOFFSET(&lp->d_partitions[part], 0);
DL_SETPSIZE(&lp->d_partitions[part], -1LL);
i = diskstrategy(sc, F_READ, LABELSECTOR, DEV_BSIZE, buf, &cnt);
if (i || cnt != DEV_BSIZE) {
printf("%s: error reading disk label\n", __func__);
goto bad;
} else if (((struct disklabel *)(buf + LABELOFFSET))->d_magic !=
DISKMAGIC) {
for (i = 0; i < MAXPARTITIONS; i++) {
DL_SETPOFFSET(&lp->d_partitions[part], 0);
DL_SETPSIZE(&lp->d_partitions[part], -1LL);
}
} else {
msg = getdisklabel(buf + LABELOFFSET, lp);
if (msg) {
printf("%s: %s\n", __func__, msg);
goto bad;
}
}
if (part >= lp->d_npartitions ||
DL_GETPSIZE(&lp->d_partitions[part]) == 0) {
bad:
free(sc, sizeof(struct disk_softc));
return (ENXIO);
}
return (0);
}
int
diskclose(struct open_file *f)
{
struct disk_softc *sc;
sc = f->f_devdata;
(void)prom_close(sc->sc_fd);
free(sc, sizeof(struct disk_softc));
f->f_devdata = NULL;
return (0);
}