Subject: CHanges to sd and cd drivers
To: None <tech-kern@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-kern
Date: 01/20/1999 16:30:49
--PEIAKu/WMn1b1Hv9
Content-Type: text/plain; charset=us-ascii
Hi,
I'd like to make a few changes to the sd and cd drivers
(patches included below):
- don't reset the SDEV_MEDIA_LOADED flag when the last partition of a sd device
is closed, but only when we believe the media has changed (cd already behaves
this way). The reset of SDEV_MEDIA_LOADED is done in the generic error
handler. This change allows to load a in-memory disklabel, and then
mount a partition. For now one would have to use a kludge to keep a parition
open while changing the disklabel, otherwise it would get lost when
'disklabel' closes the raw device.
- allows the raw partition of a sd or cd device to be opened even if
scsi_start() returns an error. The main goal here is to allow IOCTLs even
when there's no media in a removable device (for example, the CDIOCCLOSE
ioctl is totally useless for now, this is also needed for changers that don't
have a separate LUN from the drive, like ATAPI changers),
but one could want to send some commands to a disk that doesn't spin up to
help diagnose or solve the problem ...
read/write are allowed only if SDEV_MEDIA_LOADED is set, which doesn't
happen if scsipi_start() failed ...
For now only an explicit list of IOCTL are allowed when SDEV_MEDIA_LOADED
is not set. Maybe all ioctls should be allowed, letting the device return
an error if appropriate.
Another change that could be made: add SCSI_IGNORE_NOT_READY when
unlocking the device (for CDIOCALLOW, and DIOCLOCK when unlocking), to that
a CD tray could be opened by eject(1) even when no disk is loaded
(this would also require to change eject to use the raw part instead of
'a'; it could also be changed to issue CDIOCCLOSE ioctls as well).
These changes have been tested with a SCSI magneto-opetical drive and an
ATAPI CDROM, all seems to behave as expected so far. If no one complains,
I'll commit these changes next week.
--
Manuel Bouyer, LIP6, Universite Paris VI. Manuel.Bouyer@lip6.fr
--
--PEIAKu/WMn1b1Hv9
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="scsi.diff"
Index: cd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/cd.c,v
retrieving revision 1.118
diff -u -r1.118 cd.c
--- cd.c 1999/01/04 15:32:08 1.118
+++ cd.c 1999/01/20 14:59:38
@@ -70,6 +70,7 @@
#include <sys/disklabel.h>
#include <sys/disk.h>
#include <sys/cdio.h>
+#include <sys/scsiio.h>
#include <sys/proc.h>
#include <sys/conf.h>
#if NRND > 0
@@ -234,6 +235,7 @@
return (ENXIO);
sc_link = cd->sc_link;
+ part = CDPART(dev);
SC_DEBUG(sc_link, SDEV_DB1,
("cdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit,
@@ -250,7 +252,7 @@
if ((error = cdlock(cd)) != 0)
goto bad4;
- if (cd->sc_dk.dk_openmask != 0) {
+ if ((sc_link->flags & SDEV_OPEN) != 0) {
/*
* If any partition is open, but the disk has been invalidated,
* disallow further opens.
@@ -269,14 +271,22 @@
if (error)
goto bad3;
- /* Start the pack spinning if necessary. */
+ /*
+ * Start the pack spinning if necessary. Always allow the
+ * raw parition to be opened, for raw IOCTLs. Data transfers
+ * will check for SDEV_MEDIA_LOADED.
+ */
error = scsipi_start(sc_link, SSS_START,
SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE |
SCSI_SILENT);
SC_DEBUG(sc_link, SDEV_DB1,
("cdopen: scsipi_start, error=%d\n", error));
- if (error)
- goto bad3;
+ if (error) {
+ if (part != RAW_PART)
+ goto bad3;
+ else
+ goto out;
+ }
sc_link->flags |= SDEV_OPEN;
@@ -304,8 +314,6 @@
}
}
- part = CDPART(dev);
-
/* Check that the partition exists. */
if (part != RAW_PART &&
(part >= cd->sc_dk.dk_label->d_npartitions ||
@@ -314,7 +322,7 @@
goto bad;
}
- /* Insure only one open at a time. */
+out: /* Insure only one open at a time. */
switch (fmt) {
case S_IFCHR:
cd->sc_dk.dk_copenmask |= (1 << part);
@@ -408,13 +416,6 @@
SC_DEBUG(cd->sc_link, SDEV_DB1,
("%ld bytes @ blk %d\n", bp->b_bcount, bp->b_blkno));
/*
- * The transfer must be a whole number of blocks.
- */
- if ((bp->b_bcount % cd->sc_dk.dk_label->d_secsize) != 0) {
- bp->b_error = EINVAL;
- goto bad;
- }
- /*
* If the device has been made invalid, error out
* maybe the media changed
*/
@@ -423,6 +424,13 @@
goto bad;
}
/*
+ * The transfer must be a whole number of blocks.
+ */
+ if ((bp->b_bcount % cd->sc_dk.dk_label->d_secsize) != 0) {
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+ /*
* If it's a null transfer, return immediately
*/
if (bp->b_bcount == 0)
@@ -702,10 +710,40 @@
SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%lx ", cmd));
/*
- * If the device is not valid.. abandon ship
+ * If the device is not valid, some IOCTLs can still be
+ * handled on the raw partition. Check this here.
*/
- if ((cd->sc_link->flags & SDEV_MEDIA_LOADED) == 0)
- return (EIO);
+ if ((cd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
+ switch (cmd) {
+ case DIOCWLABEL:
+ case DIOCLOCK:
+ case DIOCEJECT:
+ case SCIOCIDENTIFY:
+ case OSCIOCIDENTIFY:
+ case SCIOCCOMMAND:
+ case SCIOCDEBUG:
+ case CDIOCGETVOL:
+ case CDIOCSETVOL:
+ case CDIOCSETMONO:
+ case CDIOCSETSTEREO:
+ case CDIOCSETMUTE:
+ case CDIOCSETLEFT:
+ case CDIOCSETRIGHT:
+ case CDIOCCLOSE:
+ case CDIOCALLOW:
+ case CDIOCPREVENT:
+ case CDIOCSETDEBUG:
+ case CDIOCCLRDEBUG:
+ case CDIOCRESET:
+ case SCIOCRESET:
+ case CDIOCLOADUNLOAD:
+ if (CDPART(dev) == RAW_PART)
+ break;
+ /* FALLTHROUGH */
+ default:
+ return (EIO);
+ }
+ }
switch (cmd) {
case DIOCGDINFO:
@@ -938,6 +976,7 @@
cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2);
return (0);
case CDIOCRESET:
+ case SCIOCRESET:
return (cd_reset(cd));
case CDIOCLOADUNLOAD: {
struct ioc_load_unload *args = (struct ioc_load_unload *)addr;
Index: sd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/sd.c,v
retrieving revision 1.139
diff -u -r1.139 sd.c
--- sd.c 1999/01/19 10:57:11 1.139
+++ sd.c 1999/01/20 14:59:39
@@ -63,6 +63,7 @@
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <sys/scsiio.h>
#include <sys/buf.h>
#include <sys/uio.h>
#include <sys/malloc.h>
@@ -273,10 +274,11 @@
return (ENXIO);
sc_link = sd->sc_link;
+ part = SDPART(dev);
SC_DEBUG(sc_link, SDEV_DB1,
("sdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit,
- sd_cd.cd_ndevs, SDPART(dev)));
+ sd_cd.cd_ndevs, part));
/*
* If this is the first open of this device, add a reference
@@ -289,12 +291,13 @@
if ((error = sdlock(sd)) != 0)
goto bad4;
- if (sd->sc_dk.dk_openmask != 0) {
+ if ((sc_link->flags & SDEV_OPEN) != 0) {
/*
* If any partition is open, but the disk has been invalidated,
- * disallow further opens.
+ * disallow further opens of non-raw partition
*/
- if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
+ if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0 &&
+ part != RAW_PART) {
error = EIO;
goto bad3;
}
@@ -306,12 +309,20 @@
if (error)
goto bad3;
- /* Start the pack spinning if necessary. */
+ /*
+ * Start the pack spinning if necessary. Always allow the
+ * raw parition to be opened, for raw IOCTLs. Data transfers
+ * will check for SDEV_MEDIA_LOADED.
+ */
error = scsipi_start(sc_link, SSS_START,
SCSI_IGNORE_ILLEGAL_REQUEST |
SCSI_IGNORE_MEDIA_CHANGE | SCSI_SILENT);
- if (error)
- goto bad3;
+ if (error) {
+ if (part != RAW_PART)
+ goto bad3;
+ else
+ goto out;
+ }
sc_link->flags |= SDEV_OPEN;
@@ -345,8 +356,6 @@
}
}
- part = SDPART(dev);
-
/* Check that the partition exists. */
if (part != RAW_PART &&
(part >= sd->sc_dk.dk_label->d_npartitions ||
@@ -355,7 +364,7 @@
goto bad;
}
- /* Insure only one open at a time. */
+out: /* Insure only one open at a time. */
switch (fmt) {
case S_IFCHR:
sd->sc_dk.dk_copenmask |= (1 << part);
@@ -430,7 +439,7 @@
scsipi_prevent(sd->sc_link, PR_ALLOW,
SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY);
- sd->sc_link->flags &= ~(SDEV_OPEN|SDEV_MEDIA_LOADED);
+ sd->sc_link->flags &= ~SDEV_OPEN;
scsipi_wait_drain(sd->sc_link);
@@ -457,17 +466,17 @@
SC_DEBUG(sd->sc_link, SDEV_DB1,
("%ld bytes @ blk %d\n", bp->b_bcount, bp->b_blkno));
/*
- * The transfer must be a whole number of blocks.
+ * If the device has been made invalid, error out
*/
- if ((bp->b_bcount % sd->sc_dk.dk_label->d_secsize) != 0) {
- bp->b_error = EINVAL;
+ if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
+ bp->b_error = EIO;
goto bad;
}
/*
- * If the device has been made invalid, error out
+ * The transfer must be a whole number of blocks.
*/
- if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
- bp->b_error = EIO;
+ if ((bp->b_bcount % sd->sc_dk.dk_label->d_secsize) != 0) {
+ bp->b_error = EINVAL;
goto bad;
}
/*
@@ -737,10 +746,25 @@
SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdioctl 0x%lx ", cmd));
/*
- * If the device is not valid.. abandon ship
+ * If the device is not valid, some IOCTLs can still be
+ * handled on the raw partition. Check this here.
*/
- if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0)
- return (EIO);
+ if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
+ switch (cmd) {
+ case DIOCWLABEL:
+ case DIOCLOCK:
+ case DIOCEJECT:
+ case SCIOCIDENTIFY:
+ case OSCIOCIDENTIFY:
+ case SCIOCCOMMAND:
+ case SCIOCDEBUG:
+ if (SDPART(dev) == RAW_PART)
+ break;
+ /* FALLTHROUGH */
+ default:
+ return (EIO);
+ }
+ }
switch (cmd) {
case DIOCGDINFO:
@@ -937,7 +961,7 @@
/*
* If the device is not open yet, let the generic code handle it.
*/
- if ((sc_link->flags & SDEV_OPEN) == 0) {
+ if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
return (retval);
}
@@ -1005,7 +1029,9 @@
if (omask == 0 && sdopen(dev, 0, S_IFBLK, NULL) != 0)
return (-1);
- if (sd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
+ if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0)
+ size = -1;
+ else if (sd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
size = -1;
else
size = sd->sc_dk.dk_label->d_partitions[part].p_size *
@@ -1057,16 +1083,9 @@
if (unit >= sd_cd.cd_ndevs || (sd = sd_cd.cd_devs[unit]) == NULL)
return (ENXIO);
- /*
- * XXX Can't do this check, since the media might have been
- * XXX marked `invalid' by successful unmounting of all
- * XXX filesystems.
- */
-#if 0
/* Make sure it was initialized. */
if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED)
return (ENXIO);
-#endif
/* Convert to disk sectors. Request must be a multiple of size. */
lp = sd->sc_dk.dk_label;
--PEIAKu/WMn1b1Hv9--