Subject: scsipi woes: can't call scsi command from kernel by ioctl?
To: None <tech-kern@netbsd.org>
From: Reinoud Zandijk <reinoud@netbsd.org>
List: tech-kern
Date: 08/28/2005 02:25:17
--uQr8t48UFsdbeI+V
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Dear folks,

i'm trying to call a SCIOCCOMMAND ioctl using VOP_IOCTL() on a device node 
in-kernel. To enable kernel calls i thought the following patch would be 
sufficient :

---------------------
--- scsipi_ioctl.c      1 Feb 2005 00:19:34 -0000       1.52
+++ scsipi_ioctl.c      27 Aug 2005 23:54:43 -0000
@@ -348,7 +348,7 @@
                        si->si_uio.uio_iovcnt = 1;
                        si->si_uio.uio_resid = len;
                        si->si_uio.uio_offset = 0;
-                       si->si_uio.uio_segflg = UIO_USERSPACE;
+                       si->si_uio.uio_segflg = (flag & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
                        si->si_uio.uio_rw =
                            (screq->flags & SCCMD_READ) ? UIO_READ : 
UIO_WRITE;
                        si->si_uio.uio_procp = p;

----------------------

only to find out that it uses :
			error = physio(scsistrategy, &si->si_bp, dev,
			    (screq->flags & SCCMD_READ) ? B_READ : B_WRITE,
			    periph->periph_channel->chan_adapter->adapt_minphys,
			    &si->si_uio);

to execute the command. Now this shouldn't be be problem as it passes the 
userland/kernel space flag in its uio.

Looking at physio it just bluntly ignores the uio_segflg calling the 
scsistrategy bluntly with the address provided in the uio_iov. Thus 
destroying knowledge of if it happened to be a userland of kernel space 
address.

Now in kern/kern_physio.c line 197:
                       /*
                         * [mark the buffer busy for physical I/O]
                         * (i.e. set B_PHYS (because it's an I/O to user
                         * memory, and B_RAW, because B_RAW is to be
                         * "Set by physio for raw transfers.", in addition
                         * to the "busy" and read/write flag.)
                         */
                        bp->b_flags = B_BUSY | B_PHYS | B_RAW | flags;

it aparently allways sets B_PHYS. I know these parts of the the kernel are 
deemed sacret but shouldn't this be dependent on the uio_segflg?

Why was it choosen to use physio() in the first place when its first 
getting a struct scsi_ioctl with accompanied buf, filling it in, calling 
physio that calls scsistrategy() wich lookups the struct scsi_ioctl from 
the buf and then proceeds...

Shouldn't scsistrategy() either honour the B_PHYS flag or the 
si->si_uio.uio_segflg and pass it over to scsipi_command by 
setting/clearing of the XS_CTL_USERCMD flag?

If this is not changed i'm forced to use scsipi_command() myself like
	return (scsipi_command(cd->sc_periph,
	    (void *)&cmd, sizeof(cmd), (void *)data, len, CDRETRIES,
	    30000, NULL, flags | XS_CTL_DATA_IN));

but then i'd have to figure out the struct scsipi_periph wich is a big NONO 
IMHO since it breaks abstraction and i'd be cleaner to use VOP_IOCTL(). I 
could offcource encode all nessisary SCSI commands to CDIOCTL's but 
wouldn't that explode the number of IOCTL's unnessisary?

Thoughts most appreciated,

regards,
Reinoud

--uQr8t48UFsdbeI+V
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (NetBSD)

iQEVAwUBQxEEZoKcNwBDyKpoAQLnVQf/aVQCzhQgv7RDOPw7by/2fiUUTtmYV7Y5
vvo313dlrElHfjb8Ghm7deqizn6aoNhhCEMMYfYajdetdjJQbygVzaa5xgDBuA/p
ynQBaBV+nCNiiUV6pe4m05yP792qR81vQ6AcL+40R8UUJWoAtNru6nfKWvzZ82M2
QQ/TMZln8zYDseJ8fBfUVDP/3rJViDDpHTelyeZed8sO5v1IGoGhWeBCwgTGH8V1
PSgAN/HM1J5vzJL3Z4BuBEyN/3PAuUZr3IJ10NlQx92H/Aigav3V9MiKlAwwNnLA
fm047Rd6q1Xubjr6MWFl7qy+153ZVHaQyvar2dfQrzD2e7ksPNMcmA==
=eGP2
-----END PGP SIGNATURE-----

--uQr8t48UFsdbeI+V--