git: 028b16e2088a - main - cam: better ioctl compatibility for cd

From: Warner Losh <imp_at_FreeBSD.org>
Date: Thu, 25 Jul 2024 04:49:07 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=028b16e2088a682c1abfb74fa5eb7ff64405ffff

commit 028b16e2088a682c1abfb74fa5eb7ff64405ffff
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2024-07-25 04:47:45 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-07-25 04:47:45 +0000

    cam: better ioctl compatibility for cd
    
    Unlike xpt and pass driver, there's no test for ENOTTY in cdioctl to try
    the compatbility ioctls. Add one.
    
    However, this is a disk ioctl, not a cdev ioctl. To get around this, we
    cast the struct disk * to a struct cdev * to pass through. We cast it
    back in a simple wrapper function.
    
    PR:                     198336
    Sponsored by:           Netflix
    MFC after:              2 weeks
    Differential Revision:  https://reviews.freebsd.org/D42666
    Differential Revision:  https://reviews.freebsd.org/D35312
---
 sys/cam/cam_compat.c |  6 ++++++
 sys/cam/cam_periph.c | 22 +++++++++++++++++++++-
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/sys/cam/cam_compat.c b/sys/cam/cam_compat.c
index fdb4ee8717ec..896b071f86dc 100644
--- a/sys/cam/cam_compat.c
+++ b/sys/cam/cam_compat.c
@@ -49,6 +49,12 @@
 
 #include <cam/scsi/scsi_pass.h>
 
+/*
+ * Note: struct cdev *dev parameter here is simply passed through. For cdioctl
+ * we need to pass down a struct periph * which has been cast to a cdev and that
+ * is cast back again in cdioctl_dev().
+ */
+
 static int cam_compat_handle_0x17(struct cdev *dev, u_long cmd, caddr_t addr,
     int flag, struct thread *td, d_ioctl_t *cbfnp);
 static int cam_compat_handle_0x18(struct cdev *dev, u_long cmd, caddr_t addr,
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index e957edee67f1..ed90ef91abce 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -1122,6 +1122,20 @@ cam_periph_unmapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
 	return (error);
 }
 
+static int
+cam_periph_ioctl_compat(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
+{
+	struct cam_periph *periph;
+
+	/*
+	 * For compat, we need to cast struct periph * into struct cdev *dev and
+	 * then back again.
+	 */
+	periph = (struct cam_periph *)(void *)dev;
+	cam_periph_assert(periph, MA_OWNED);
+	return (cam_periph_ioctl(periph, cmd, addr, cderror));
+}
+
 int
 cam_periph_ioctl(struct cam_periph *periph, u_long cmd, caddr_t addr,
 		 int (*error_routine)(union ccb *ccb, 
@@ -1178,7 +1192,13 @@ cam_periph_ioctl(struct cam_periph *periph, u_long cmd, caddr_t addr,
 
 		break;
 	default:
-		error = ENOTTY;
+		/*
+		 * We assume that the compat layer doesn't care about
+		 * the dev parameter. It just passes it through, so
+		 * cheat a little.
+		 */
+		error = cam_compat_ioctl((struct cdev *)(void *)periph,
+		    cmd, addr, flag, td, cam_periph_ioctl_compat);
 		break;
 	}
 	return(error);