#include <lib/libsa/stand.h>
#include <sys/param.h>
#include <sys/disklabel.h>
#include <machine/rpb.h>
#include <machine/prom.h>
#include "disk.h"
struct disk_softc {
int sc_fd;
int sc_ctlr;
int sc_unit;
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;
if ((reqcnt & 0xffffff) != reqcnt ||
reqcnt == 0)
asm("call_pal 0");
twiddle();
if (reqcnt & (DEV_BSIZE - 1)) {
*cnt = 0;
return (EINVAL);
}
sc = (struct disk_softc *)devdata;
pp = &sc->sc_label.d_partitions[sc->sc_part];
if (rw == F_READ)
ret.bits = prom_read(sc->sc_fd, reqcnt, addr, bn + pp->p_offset);
else
ret.bits = prom_write(sc->sc_fd, reqcnt, addr, bn + pp->p_offset);
if (ret.u.status)
return (EIO);
if (cnt)
*cnt = ret.u.retval;
return (0);
}
int
diskopen(struct open_file *f, int ctlr, int unit, int part)
{
struct disklabel *lp;
prom_return_t ret;
size_t cnt;
int devlen, i;
char *msg, buf[DEV_BSIZE], devname[32];
struct disk_softc *sc;
if (unit >= 16 || part >= MAXPARTITIONS)
return (ENXIO);
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_ctlr = ctlr;
sc->sc_unit = unit;
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], 0x7fffffff);
i = diskstrategy(sc, F_READ,
LABELSECTOR, DEV_BSIZE, buf, &cnt);
if (i || cnt != DEV_BSIZE) {
printf("disk%d: error reading disk label\n", unit);
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], 0x7fffffff);
}
} else {
msg = getdisklabel(buf + LABELOFFSET, lp);
if (msg) {
printf("disk%d: %s\n", unit, 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);
}