Add a generic and general ioctl pass-through mechanism.

It should now be posible to issue ioctls to SCSI CD drives.
This commit is contained in:
Poul-Henning Kamp 2002-03-16 09:24:19 +00:00
parent a681ab0abe
commit a5b2e75d32
4 changed files with 85 additions and 51 deletions

View file

@ -247,6 +247,12 @@ void * g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error
/* geom_kern.c / geom_kernsim.c */
void g_init(void);
struct g_ioctl {
u_long cmd;
void *data;
int fflag;
struct thread *td;
};
#ifdef _KERNEL
@ -272,7 +278,7 @@ g_free(void *ptr)
}
extern struct sx topology_lock;
#define g_topology_lock() sx_xlock(&topology_lock)
#define g_topology_lock() do { mtx_assert(&Giant, MA_NOTOWNED); sx_xlock(&topology_lock); } while (0)
#define g_topology_unlock() sx_xunlock(&topology_lock)
#define g_topology_assert() sx_assert(&topology_lock, SX_XLOCKED)

View file

@ -89,20 +89,42 @@ g_bsd_start(struct bio *bp)
struct g_bsd_softc *ms;
struct g_slicer *gsp;
struct partinfo pi;
struct g_ioctl *gio;
gp = bp->bio_to->geom;
gsp = gp->softc;
ms = gsp->softc;
#if 0
if (g_haveattr(bp, "IOCTL::DIOCGDINFO",
&ms->inram,
sizeof ms->inram))
return (1);
if (!strcmp(bp->bio_attribute, "IOCTL::DIOCGPART")) {
else if (!strcmp(bp->bio_attribute, "IOCTL::DIOCGPART")) {
pi.disklab = &ms->inram;
pi.part = &ms->inram.d_partitions[bp->bio_to->index];
if (g_haveattr(bp, "IOCTL::DIOCGPART", &pi, sizeof pi))
return (1);
}
#endif
if (strcmp(bp->bio_attribute, "GEOM::ioctl"))
return(0);
else if (bp->bio_length != sizeof *gio)
return(0);
gio = (struct g_ioctl *)bp->bio_data;
if (gio->cmd == DIOCGDINFO) {
bcopy(&ms->inram, gio->data, sizeof ms->inram);
bp->bio_error = 0;
g_io_deliver(bp);
return (1);
}
if (gio->cmd == DIOCGPART) {
pi.disklab = &ms->inram;
pi.part = &ms->inram.d_partitions[bp->bio_to->index];
bcopy(&pi, gio->data, sizeof pi);
bp->bio_error = 0;
g_io_deliver(bp);
return (1);
}
return (0);
}

View file

@ -35,7 +35,6 @@
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@ -50,7 +49,6 @@
#include <sys/fcntl.h>
#include <geom/geom.h>
#define CDEV_MAJOR 4
static d_open_t g_dev_open;
@ -131,11 +129,9 @@ g_dev_taste(struct g_method *mp, struct g_provider *pp, struct thread *tp __unus
struct g_geom *gp;
struct g_consumer *cp;
static int unit;
#if 1
u_int secsize;
off_t mediasize;
int error, j;
#endif
dev_t dev;
g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
@ -146,7 +142,6 @@ g_dev_taste(struct g_method *mp, struct g_provider *pp, struct thread *tp __unus
gp = g_new_geomf(mp, pp->name);
cp = g_new_consumer(gp);
g_attach(cp, pp);
#if 1
error = g_access_rel(cp, 1, 0, 0);
g_topology_unlock();
if (!error) {
@ -171,17 +166,12 @@ g_dev_taste(struct g_method *mp, struct g_provider *pp, struct thread *tp __unus
secsize = 512;
mediasize = 0;
}
#else
g_topology_unlock();
#endif
mtx_lock(&Giant);
#if 1
if (mediasize != 0)
printf("GEOM: \"%s\" %lld bytes in %lld sectors of %u bytes\n",
pp->name, mediasize, mediasize / secsize, secsize);
else
printf("GEOM: \"%s\" (size unavailable)\n", pp->name);
#endif
dev = make_dev(&g_dev_cdevsw, unit++,
UID_ROOT, GID_WHEEL, 0600, gp->name);
gp->softc = dev;
@ -249,22 +239,38 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
{
struct g_geom *gp;
struct g_consumer *cp;
char *nm;
int i, error;
struct g_ioctl *gio;
gp = dev->si_drv1;
cp = dev->si_drv2;
error = 0;
mtx_unlock(&Giant);
switch (cmd) {
case DIOCGDINFO: nm = "IOCTL::DIOCGDINFO"; break;
case DIOCGDVIRGIN: nm = "IOCTL::DIOCGDVIRGIN"; break;
case DIOCGPART: nm = "IOCTL::DIOCGPART"; break;
default: nm = "?"; break;
gio = g_malloc(sizeof *gio, M_WAITOK);
gio->cmd = cmd;
gio->data = data;
gio->fflag = fflag;
gio->td = td;
i = sizeof *gio;
if (cmd & IOC_IN)
error = g_io_setattr("GEOM::ioctl", cp, i, gio, td);
else
error = g_io_getattr("GEOM::ioctl", cp, &i, gio, td);
g_free(gio);
if (error == 0) {
if (error != 0 && cmd == DIOCGDVIRGIN) {
g_topology_lock();
gp = g_create_geomf("BSD-method", cp->provider, NULL);
g_topology_unlock();
}
}
i = IOCGROUP(cmd);
if (*nm == '?') {
mtx_lock(&Giant);
g_rattle();
if (error == ENOIOCTL) {
i = IOCGROUP(cmd);
printf("IOCTL(0x%lx) \"%s\"", cmd, gp->name);
if (i > ' ' && i <= '~')
printf(" '%c'", (int)IOCGROUP(cmd));
@ -275,23 +281,9 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
printf("I");
if (cmd & IOC_OUT)
printf("O");
printf("(%ld)", IOCPARM_LEN(cmd));
printf(" \"%s\"\n", nm);
error = ENOIOCTL;
}
if (error == 0) {
i = IOCPARM_LEN(cmd);
error = g_io_getattr(nm, cp, &i, data, td);
if (error != 0 && cmd == DIOCGDVIRGIN) {
g_topology_lock();
gp = g_create_geomf("BSD-method", cp->provider, NULL);
g_topology_unlock();
}
}
mtx_lock(&Giant);
g_rattle();
if (error == ENOIOCTL)
printf("(%ld) = ENOIOCTL\n", IOCPARM_LEN(cmd));
error = ENOTTY;
}
return (error);
}

View file

@ -115,9 +115,12 @@ g_disk_start(struct bio *bp)
struct bio *bp2;
dev_t dev;
struct disk *dp;
struct g_ioctl *gio;
int error;
dp = bp->bio_to->geom->softc;
dev = dp->d_dev;
error = 0;
switch(bp->bio_cmd) {
case BIO_READ:
case BIO_WRITE:
@ -134,27 +137,38 @@ g_disk_start(struct bio *bp)
case BIO_GETATTR:
if (g_haveattr_int(bp, "GEOM::sectorsize",
dp->d_label.d_secsize))
return;
if (g_haveattr_int(bp, "GEOM::fwsectors",
break;
else if (g_haveattr_int(bp, "GEOM::fwsectors",
dp->d_label.d_nsectors))
return;
if (g_haveattr_int(bp, "GEOM::fwheads",
break;
else if (g_haveattr_int(bp, "GEOM::fwheads",
dp->d_label.d_ntracks))
return;
if (g_haveattr_int(bp, "GEOM::fwcylinders",
break;
else if (g_haveattr_int(bp, "GEOM::fwcylinders",
dp->d_label.d_ncylinders))
return;
if (g_haveattr_off_t(bp, "GEOM::mediasize",
break;
else if (g_haveattr_off_t(bp, "GEOM::mediasize",
dp->d_label.d_secsize * (off_t)dp->d_label.d_secperunit))
return;
bp->bio_error = ENOIOCTL;
g_io_deliver(bp);
return;
break;
else if (!strcmp(bp->bio_attribute, "GEOM::ioctl") &&
bp->bio_length == sizeof *gio) {
gio = (struct g_ioctl *)bp->bio_data;
mtx_lock(&Giant);
error = devsw(dev)->d_ioctl(dev, gio->cmd,
gio->data, gio->fflag, gio->td);
mtx_unlock(&Giant);
} else
error = ENOIOCTL;
break;
default:
bp->bio_error = EOPNOTSUPP;
g_io_deliver(bp);
return;
error = EOPNOTSUPP;
break;
}
if (error) {
bp->bio_error = error;
g_io_deliver(bp);
}
return;
}
dev_t