summaryrefslogtreecommitdiffstats
path: root/sys/scsi
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1993-11-18 05:03:27 +0000
committerrgrimes <rgrimes@FreeBSD.org>1993-11-18 05:03:27 +0000
commit73dd2628a2d9f88e008196681e15c6d3a0dc11be (patch)
tree6d93e911e7337a8936028ed9a12d64183f6766d3 /sys/scsi
parentdbf6b5a2db39d182aba158f88c9cd5005db5d6e0 (diff)
downloadFreeBSD-src-73dd2628a2d9f88e008196681e15c6d3a0dc11be.zip
FreeBSD-src-73dd2628a2d9f88e008196681e15c6d3a0dc11be.tar.gz
New version of scsi code from Julian
Diffstat (limited to 'sys/scsi')
-rw-r--r--sys/scsi/README189
-rw-r--r--sys/scsi/cd.c2246
-rw-r--r--sys/scsi/ch.c1204
-rw-r--r--sys/scsi/scsi_all.h93
-rw-r--r--sys/scsi/scsi_base.c852
-rw-r--r--sys/scsi/scsi_cd.h10
-rw-r--r--sys/scsi/scsi_changer.h9
-rw-r--r--sys/scsi/scsi_debug.h53
-rw-r--r--sys/scsi/scsi_disk.h11
-rw-r--r--sys/scsi/scsi_ioctl.c329
-rw-r--r--sys/scsi/scsi_tape.h12
-rw-r--r--sys/scsi/scsiconf.c1110
-rw-r--r--sys/scsi/scsiconf.h259
-rw-r--r--sys/scsi/sd.c2072
-rw-r--r--sys/scsi/st.c3439
-rw-r--r--sys/scsi/su.c4
-rw-r--r--sys/scsi/uk.c156
17 files changed, 5668 insertions, 6380 deletions
diff --git a/sys/scsi/README b/sys/scsi/README
index fbd1e6e..b110930 100644
--- a/sys/scsi/README
+++ b/sys/scsi/README
@@ -1,46 +1,55 @@
This release consists of the following files
-(relative to the base of the kernel tree)
-
-
-MAKEDEV
-
-scsi
-scsi/README
-scsi/scsiconf.h
-scsi/scsiconf.c
-scsi/scsi_all.h
-
-scsi/scsi_disk.h
-scsi/sd.c
-
-sys/mtio.h (modified)
-scsi/scsi_tape.h
-scsi/st.c
-
-sys/sgio.h
-scsi/scsi_generic.h
-scsi/sg.c /* port not complete */
-
-sys/chio.h
-scsi/scsi_changer.h
-scsi/ch.c
-
-sys/cdio.h
-scsi/scsi_cd.h
-scsi/cd.c
-
-i386/conf/SCSITEST
-i386/isa/aha1542.c
-
-i386/conf/AHBTEST
-i386/isa/aha1742.c
-
-i386/conf/UHATEST
-i386/isa/ultra14f.c
-
-i386/conf/BTTEST
-i386/isa/bt742a.c
-
+(relative to the base of the source tree )
+
+share/man/man4/scsi.4 <-useful general info
+share/man/man4/uk.4
+share/man/man4/su.4
+share/man/man4/ch.4
+share/man/man4/cd.4
+share/man/man4/sd.4
+share/man/man4/st.4 <--READ THIS IF YOU USE TAPES!
+sbin/scsi/procargs.c
+sbin/scsi/scsi.c
+sbin/scsi/scsi.1
+sbin/scsi/Makefile
+sbin/st/Makefile
+sbin/st/st.1
+sbin/st/st.c
+sys/sys/chio.h
+sys/sys/cdio.h
+sys/sys/mtio.h
+sys/sys/scsiio.h
+sys/i386/conf/EXAMPLE
+sys/i386/isa/ultra14f.c <-runs 14f and 34f
+sys/i386/isa/ultra_all.c.beta <-beta version, runs 14f,24f and 34f
+sys/i386/isa/bt742a.c
+sys/i386/isa/aha1742.c
+sys/i386/isa/aha1542.c
+sys/scsi/syspatches
+sys/scsi/syspatches/conf.c
+sys/scsi/syspatches/user_scsi.diffs
+sys/scsi/syspatches/MAKEDEV.diff
+sys/scsi/syspatches/isa.c.patch
+sys/scsi/syspatches/README
+sys/scsi/uk.c
+sys/scsi/su.c
+sys/scsi/st.c
+sys/scsi/sd.c
+sys/scsi/ch.c
+sys/scsi/cd.c
+sys/scsi/scsi_ioctl.c
+sys/scsi/scsi_base.c
+sys/scsi/scsiconf.c
+sys/scsi/scsi_tape.h
+sys/scsi/scsi_disk.h
+sys/scsi/scsi_changer.h
+sys/scsi/scsi_cd.h
+sys/scsi/scsi_all.h
+sys/scsi/scsi_debug.h
+sys/scsi/scsiconf.h
+sys/scsi/README <--this file
+
+notice sys/scsi/sg.c and sys/sys/sgio.h have been removed
----------------------------------------------------------------
@@ -54,34 +63,22 @@ generic scsi tape
cd-rom (plays music under the xcplayer (?) program)
AEG Character recognition devices *
Calera Character recognition devices *
-Kodak IL900 scanner *
+Generic scsi-II scanners *
Exabyte tape changer device.
-GENERIC SCSI DEVICES (user generated scsi commands) (port not complete)
+GENERIC SCSI DEVICES (user generated scsi commands)
----------------------------------------------------------------
There are also working bottom end drivers for:
----------------------------------------------------------------
adaptec 1542 (and 1742 in 1542 mode)
-bustec 742a (apparently works for VESA version)
-adaptec 174x
+bustec 742a (apparently works for VESA version (445S?))(and 747?)
+adaptec 174x (note NOT 27xx)
Ultrastore 14f (works for 34f (VESA version))
+Ultrastore 24f RSN (Beta version included here)
----------------------------------------------------------------
-Work is proceeding on the following bottom end drivers:
-----------------------------------------------------------------
-Future Domain (1680)** hosler@tfs.com & me
-Future Domain (8 bit)**** rpr@oce.nl
-WD7000** terry@icarus.weber.edu
-seagate st01/st02**** overby@aspen.cray.com ?
-----------------------------------------------------------------
-* drivers not made public (proprietary.. proof that the concept works though)
-** driver not yet released but working.
-*** just a dream so far.
-**** some amount more than just a dream so far.
-
-
################## Using the scsi system ##################
------------minor numbers---------------
This scsi system does not allocate minor numbers to devices depending
@@ -98,19 +95,18 @@ That would not change their minor numbers.
THE EXCEPTION TO THIS IS IN THE GENERIC SCSI DRIVER. in which case
the following mapping applies:
-BB LLL TTT B= scsi bus number, T = target number, L = LUN.
-(yes I know it's strange but it's SGI compatible)
+BB TTT LLL B= scsi bus number, T = target number, L = LUN.
It is possible to run two different TYPES of scsi adapters at the
same time and have st0 on one and st1 on another. (for example)
There is a scheme supported in which scsi devices can be 'wired in' even
if they are not present or powered on at probe time. (see scsiconf.c)
+In addition, the scsi(1) command allows the operator ask for a
+reprobe at any time. Newly found devices will be configured in. Any
+device that does not map to a known device type is attached to the
+'unknown' (uk) driver.
---------------getting started------------
-It should be possible to use the /dev entries for as0 as if they were
-/dev entries for sd0 and the old as bootblocks should
-continue to work if you are using an adaptec 1542b.
--------------making devices------------
A changed version of /dev/MAKEDEV is supplied that
@@ -120,25 +116,7 @@ e.g.
cd /dev
sh MAKEDEV sd0 sd1 sd2 st0 st1 cd0
-
-The tape devices are as follows:
-rst0 basic raw device, will rewind on close
-nrst0 will not rewind on close
-erst0 will rewind and EJECTon close
-nerst0 will not rewind and WILL eject (some devices may rewind anyhow)
-
-------------future enhancements--------------
-Some people have indicated that they would like to have the SCSI ID
-encoded into the minor number in some way, and
-this may be supported at some timein the future, using
-minor numbers greater than 128. (or maybe a different major number)
-
-
-I will also be writing (probably) a generic scsi-error
-handling routine that will be table driven, so that the routine can
-be removed from each individual driver. With enough care,
-two similar devices with different error codes (quite common) could run
-the same driver but use different error tables.
+see st(1) and st(4) for info on tape devices.
--------------file layout-------------------
Originally I had all scsi definitions in one file: scsi.h
@@ -159,18 +137,22 @@ scsi-changer.h commands medium changer devices --- CHAPTER 16
User accessable structures (e.g. ioctl definitions) have been
placed in sys/cdio, sys/sgio and sys/chio (based after sys/mtio for
the ioctls for mag tapes (including st).
+General scsi ioctls are found in sys/scsiio.h.
-----------cd-rom-----------------
The cd rom driver ha been tested by a number of people and
-grefen@wilbur.zdv.uni-mainz.de has completed the audio play
+grefen@convex.com has completed the audio play
functions.
(xcdplayer was available from the 'from_ref' directory on agate)
At this time it is possible audio play is broken on cdroms and I will
be unable to fix it until I get one to test.
+***IMPORTANT***
+Cdrom audio is only suported at all for cdroms that use SCSI2 audio
+definitions.
-------------media changer---------------
-Once again courtesy of grefen@wilbur.zdv.uni-mainz.de.
+Once again courtesy of grefen@convex.com (in germany)
I have not tested this but he assures me it's ready for testing.
If anyone has an exabyte tape changer or similar,
contact the author for information regarding the control interface
@@ -178,20 +160,6 @@ and program.
WARNING: This has not been tested for a LONG TIME!
------------booting from an AHA-174x---------
-For some reason I have not yet worked out,
-the BIOS-based bootblocks I have posted will not boot
-from the aha1742 in extended mode. (it can't be serious
-because the MACH version works) This is in fact not a
-problem because the aha1742 driver will force the board into extended
-mode during probe, so it can be left in standard mode during the boot.
-During the next reboot, the bios will place it back in standard mode
-ready for the NEXT boot.
-
-[Update: This has apparently been fixed in the newest NetBSD/FreeBSD
-releases ]
-
-
---------recent changes-----------
Removed all bitfields from machine independent sections to make
@@ -206,4 +174,23 @@ have particular problems so they can be handled specially.
many bug-fixes and cleanups.
-$Id$
+---------even more recent changes:--------
+
+rewrote almost the entire thing..
+
+
+
+------Mon Oct 11 22:20:25 WST 1993------
+
+Code is now all KNF (or close to it).
+
+A new structure has been introduced..
+Called scsi_link, one of these exists for every bus/target/lun
+that has a driver attached to it.
+It has links to the adapter and to the driver, as well as status
+information of global interest. (e.g. if the device is in use).
+The use of this new structure has allowed the compaction of a
+lot of duplicated code into a single copy (now in scsi_base.c)
+and makes more simple the USER level scsi implimentation.
+
+
diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c
index f5de591..68b09ba 100644
--- a/sys/scsi/cd.c
+++ b/sys/scsi/cd.c
@@ -14,7 +14,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: cd.c,v 1.10 1993/09/21 05:30:35 rgrimes Exp $
+ * $Id: cd.c,v 2.3 93/10/11 11:49:49 julian Exp Locker: julian $
*/
#define SPLCD splbio
@@ -40,898 +40,697 @@
#include <scsi/scsi_disk.h> /* rw_big and start_stop come from there */
#include <scsi/scsiconf.h>
-long int cdstrats,cdqueues;
-
+int32 cdstrats, cdqueues;
#include <ddb.h>
#if NDDB > 0
-int Debugger();
-#else NDDB > 0
+int Debugger();
+#else /* NDDB > 0 */
#define Debugger()
-#endif NDDB > 0
-
+#endif /* NDDB > 0 */
#define PAGESIZ 4096
-#define SECSIZE 2048 /* XXX */ /* default only */
+#define SECSIZE 2048 /* XXX */ /* default only */
#define CDOUTSTANDING 2
-#define CDQSIZE 4
-#define CD_RETRIES 4
+#define CDRETRIES 1
#define UNITSHIFT 3
#define PARTITION(z) (minor(z) & 0x07)
#define RAW_PART 3
#define UNIT(z) ( (minor(z) >> UNITSHIFT) )
+extern int hz;
+errval cdstrategy();
-extern int hz;
-int cd_done();
-int cdstrategy();
-int cd_debug = 0;
-
-
-struct cd_data
+void cdstart();
+struct scsi_device cd_switch =
{
- int flags;
-#define CDVALID 0x02 /* PARAMS LOADED */
-#define CDINIT 0x04 /* device has been init'd */
-#define CDWAIT 0x08 /* device has someone waiting */
-#define CDHAVELABEL 0x10 /* have read the label */
- struct scsi_switch *sc_sw; /* address of scsi low level switch */
- int ctlr; /* so they know which one we want */
- int targ; /* our scsi target ID */
- int lu; /* out scsi lu */
- int cmdscount; /* cmds allowed outstanding by board*/
- struct cd_parms
- {
- int blksize;
- u_long disksize; /* total number sectors */
- }params;
- struct disklabel disklabel;
- int partflags[MAXPARTITIONS]; /* per partition flags */
+ NULL, /* use default error handler */
+ cdstart, /* we have a queue, which is started by this */
+ NULL, /* we do not have an async handler */
+ NULL, /* use default 'done' routine */
+ "cd", /* we are to be refered to by this name */
+ 0, /* no device specific flags */
+ 0, 0 /* spares not used */
+};
+
+struct cd_data {
+ u_int32 flags;
+#define CDINIT 0x04 /* device has been init'd */
+ struct scsi_link *sc_link; /* address of scsi low level switch */
+ u_int32 cmdscount; /* cmds allowed outstanding by board */
+ struct cd_parms {
+ u_int32 blksize;
+ u_long disksize; /* total number sectors */
+ } params;
+ struct disklabel disklabel;
+ u_int32 partflags[MAXPARTITIONS]; /* per partition flags */
#define CDOPEN 0x01
- int openparts; /* one bit for each open partition */
- int xfer_block_wait;
- struct scsi_xfer *free_xfer;
- struct scsi_xfer scsi_xfer[CDOUTSTANDING]; /* XXX */
- struct buf buf_queue;
+ u_int32 openparts; /* one bit for each open partition */
+ u_int32 xfer_block_wait;
+ struct buf buf_queue;
};
#define CD_STOP 0
#define CD_START 1
#define CD_EJECT -2
-struct cd_driver
-{
- int size;
- struct cd_data **cd_data;
-}*cd_driver;
-
-static int next_cd_unit = 0;
-/***********************************************************************\
-* The routine called by the low level scsi routine when it discovers *
-* A device suitable for this driver *
-\***********************************************************************/
-int cdattach(ctlr,targ,lu,scsi_switch)
-struct scsi_switch *scsi_switch;
+struct cd_driver {
+ u_int32 size;
+ struct cd_data **cd_data;
+} cd_driver;
+
+static u_int32 next_cd_unit = 0;
+
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * A device suitable for this driver
+ */
+int
+cdattach(sc_link)
+ struct scsi_link *sc_link;
{
- int unit,i;
- unsigned char *tbl;
- struct cd_data *cd, **cdrealloc;
- struct cd_parms *dp;
-
-#ifdef CDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("cdattach: ");
-#endif /*CDDEBUG*/
- /*******************************************************\
- * Check if we have resources allocated yet, if not *
- * allocate and initialize them *
- \*******************************************************/
- if (next_cd_unit == 0)
- {
- cd_driver =
- malloc(sizeof(struct cd_driver),M_DEVBUF,M_NOWAIT);
- if(!cd_driver)
- {
- printf("cd%d: malloc failed for cd_driver\n",unit);
- return(0);
- }
- bzero(cd_driver,sizeof(cd_driver));
- cd_driver->size = 0;
- }
- /*******************************************************\
- * allocate the resources for another drive *
- * if we have already allocate a cd_data pointer we must *
- * copy the old pointers into a new region that is *
- * larger and release the old region, aka realloc *
- \*******************************************************/
+ u_int32 unit, i;
+ unsigned char *tbl;
+ struct cd_data *cd, **cdrealloc;
+ struct cd_parms *dp;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("cdattach "));
+
+ /*
+ * Fill out any more info in the
+ * Link structure that we can
+ */
unit = next_cd_unit++;
+ sc_link->device = &cd_switch;
+ sc_link->dev_unit = unit;
+ /*
+ * allocate the resources for another drive
+ * if we have already allocate a cd_data pointer we must
+ * copy the old pointers into a new region that is
+ * larger and release the old region, aka realloc
+ */
/* XXX
* This if will always be true for now, but future code may
* preallocate more units to reduce overhead. This would be
* done by changing the malloc to be (next_cd_unit * x) and
- * the cd_driver->size++ to be +x
+ * the cd_driver.size++ to be +x
*/
- if(unit >= cd_driver->size)
- {
+ if (unit >= cd_driver.size) {
cdrealloc =
- malloc(sizeof(cd_driver->cd_data) * next_cd_unit,
- M_DEVBUF,M_NOWAIT);
- if(!cdrealloc)
- {
- printf("cd%d: malloc failed for cdrealloc\n",unit);
- return(0);
+ malloc(sizeof(cd_driver.cd_data) * next_cd_unit,
+ M_DEVBUF, M_NOWAIT);
+ if (!cdrealloc) {
+ printf("cd%d: malloc failed for cdrealloc\n", unit);
+ return (0);
}
/* Make sure we have something to copy before we copy it */
- bzero(cdrealloc,sizeof(cd_driver->cd_data) * next_cd_unit);
- if(cd_driver->size)
- {
- bcopy(cd_driver->cd_data,cdrealloc,
- sizeof(cd_driver->cd_data) * cd_driver->size);
- free(cd_driver->cd_data,M_DEVBUF);
+ bzero(cdrealloc, sizeof(cd_driver.cd_data) * next_cd_unit);
+ if (cd_driver.size) {
+ bcopy(cd_driver.cd_data, cdrealloc,
+ sizeof(cd_driver.cd_data) * cd_driver.size);
+ free(cd_driver.cd_data, M_DEVBUF);
}
- cd_driver->cd_data = cdrealloc;
- cd_driver->cd_data[unit] = NULL;
- cd_driver->size++;
- }
- if(cd_driver->cd_data[unit])
- {
- printf("cd%d: Already has storage!\n",unit);
- return(0);
+ cd_driver.cd_data = cdrealloc;
+ cd_driver.cd_data[unit] = NULL;
+ cd_driver.size++;
}
- /*******************************************************\
- * allocate the per drive data area *
- \*******************************************************/
- cd = cd_driver->cd_data[unit] =
- malloc(sizeof(struct cd_data),M_DEVBUF,M_NOWAIT);
- if(!cd)
- {
- printf("cd%d: malloc failed for cd_data\n",unit);
- return(0);
+ if (cd_driver.cd_data[unit]) {
+ printf("cd%d: Already has storage!\n", unit);
+ return (0);
}
- bzero(cd,sizeof(struct cd_data));
- dp = &(cd->params);
- /*******************************************************\
- * Store information needed to contact our base driver *
- \*******************************************************/
- cd->sc_sw = scsi_switch;
- cd->ctlr = ctlr;
- cd->targ = targ;
- cd->lu = lu;
- cd->cmdscount = CDOUTSTANDING; /* XXX (ask the board) */
-
- i = cd->cmdscount;
- while(i-- )
- {
- cd->scsi_xfer[i].next = cd->free_xfer;
- cd->free_xfer = &cd->scsi_xfer[i];
+ /*
+ * allocate the per drive data area
+ */
+ cd = cd_driver.cd_data[unit] =
+ malloc(sizeof(struct cd_data), M_DEVBUF, M_NOWAIT);
+ if (!cd) {
+ printf("cd%d: malloc failed for cd_data\n", unit);
+ return (0);
}
- /*******************************************************\
- * Use the subdriver to request information regarding *
- * the drive. We cannot use interrupts yet, so the *
- * request must specify this. *
- \*******************************************************/
- cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
- if(dp->disksize)
- {
+ bzero(cd, sizeof(struct cd_data));
+ dp = &(cd->params);
+ /*
+ * Store information needed to contact our base driver
+ */
+ cd->sc_link = sc_link;
+ /* only allow 1 outstanding command on tapes */
+ sc_link->opennings = cd->cmdscount = CDOUTSTANDING;
+
+ /*
+ * Use the subdriver to request information regarding
+ * the drive. We cannot use interrupts yet, so the
+ * request must specify this.
+ */
+ cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
+ if (dp->disksize) {
printf("cd%d: cd present.[%d x %d byte records]\n",
- unit,
- cd->params.disksize,
- cd->params.blksize);
- }
- else
- {
+ unit,
+ cd->params.disksize,
+ cd->params.blksize);
+ } else {
printf("cd%d: drive empty\n", unit);
}
cd->flags |= CDINIT;
- return;
+ return (1);
}
-/*******************************************************\
-* open the device. Make sure the partition info *
-* is a up-to-date as can be. *
-\*******************************************************/
+/*
+ * open the device. Make sure the partition info is a up-to-date as can be.
+ */
+errval
cdopen(dev)
{
- int errcode = 0;
- int unit, part;
+ errval errcode = 0;
+ u_int32 unit, part;
struct cd_parms cd_parms;
struct cd_data *cd;
+ struct scsi_link *sc_link;
+ u_int32 heldflags;
unit = UNIT(dev);
part = PARTITION(dev);
-#ifdef CDDEBUG
- if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
- printf("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n"
- ,dev,unit,cd_driver->size,part);
-#endif /*CDDEBUG*/
- /*******************************************************\
- * Check the unit is legal *
- \*******************************************************/
- if ( unit >= cd_driver->size )
- {
- return(ENXIO);
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= cd_driver.size) {
+ return (ENXIO);
}
- cd = cd_driver->cd_data[unit];
- /*******************************************************\
- * Make sure the device has been initialised *
- \*******************************************************/
+ cd = cd_driver.cd_data[unit];
+ /*
+ * Make sure the device has been initialised
+ */
if ((cd == NULL) || (!(cd->flags & CDINIT)))
- return(ENXIO);
-
- /*******************************************************\
- * If it's been invalidated, and not everybody has *
- * closed it then forbid re-entry. *
- * (may have changed media) *
- \*******************************************************/
- if ((! (cd->flags & CDVALID))
- && ( cd->openparts))
- return(ENXIO);
-
- /*******************************************************\
- * Check that it is still responding and ok. *
- * if the media has been changed this will result in a *
- * "unit attention" error which the error code will *
- * disregard because the CDVALID flag is not yet set *
- \*******************************************************/
- cd_test_ready(unit, SCSI_SILENT);
-
- /*******************************************************\
- * Next time actually take notice of error returns *
- \*******************************************************/
- if (cd_test_ready(unit, SCSI_SILENT) != 0) {
-#ifdef CDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("not ready\n");
-#endif /*CDDEBUG*/
- return(ENXIO);
+ return (ENXIO);
+
+ sc_link = cd->sc_link;
+ SC_DEBUG(sc_link, SDEV_DB1,
+ ("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n",
+ dev, unit, cd_driver.size, part));
+ /*
+ * If it's been invalidated, and not everybody has closed it then
+ * forbid re-entry. (may have changed media)
+ */
+ if ((!(sc_link->flags & SDEV_MEDIA_LOADED))
+ && (cd->openparts))
+ return (ENXIO);
+
+ /*
+ * Check that it is still responding and ok.
+ * if the media has been changed this will result in a
+ * "unit attention" error which the error code will
+ * disregard because the SDEV_MEDIA_LOADED flag is not yet set
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ /*
+ * Next time actually take notice of error returns
+ */
+ sc_link->flags |= SDEV_OPEN; /* unit attn errors are now errors */
+ if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n"));
+ errcode = ENXIO;
+ goto bad;
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("Device present\n"));
+ /*
+ * In case it is a funny one, tell it to start
+ * not needed for some drives
+ */
+ scsi_start_unit(sc_link, CD_START);
+ scsi_prevent(sc_link, PR_PREVENT, SCSI_SILENT);
+ SC_DEBUG(sc_link, SDEV_DB3, ("started "));
+ /*
+ * Load the physical device parameters
+ */
+ if (cd_get_parms(unit, 0)) {
+ errcode = ENXIO;
+ goto bad;
}
-#ifdef CDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("Device present\n");
-#endif /*CDDEBUG*/
- /*******************************************************\
- * In case it is a funny one, tell it to start *
- * not needed for some drives *
- \*******************************************************/
- cd_start_unit(unit,part,CD_START);
- cd_prevent_unit(unit,PR_PREVENT,SCSI_SILENT);
-#ifdef CDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("started ");
-#endif /*CDDEBUG*/
- /*******************************************************\
- * Load the physical device parameters *
- \*******************************************************/
- cd_get_parms(unit, 0);
-#ifdef CDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("Params loaded ");
-#endif /*CDDEBUG*/
- /*******************************************************\
- * Load the partition info if not already loaded *
- \*******************************************************/
+ SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded "));
+ /*
+ * Make up some partition information
+ */
cdgetdisklabel(unit);
-#ifdef CDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("Disklabel fabricated ");
-#endif /*CDDEBUG*/
- /*******************************************************\
- * Check the partition is legal *
- \*******************************************************/
- if (( part >= cd->disklabel.d_npartitions )
- && (part != RAW_PART))
- {
-#ifdef CDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("partition %d > %d\n",part
- ,cd->disklabel.d_npartitions);
-#endif /*CDDEBUG*/
- cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT);
- return(ENXIO);
+ SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel fabricated "));
+ /*
+ * Check the partition is legal
+ */
+ if ((part >= cd->disklabel.d_npartitions)
+ && (part != RAW_PART)) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("partition %d > %d\n", part
+ ,cd->disklabel.d_npartitions));
+ errcode = ENXIO;
+ goto bad;
}
- /*******************************************************\
- * Check that the partition exists *
- \*******************************************************/
- if (( cd->disklabel.d_partitions[part].p_fstype != FS_UNUSED )
- || (part == RAW_PART))
- {
- cd->partflags[part] |= CDOPEN;
- cd->openparts |= (1 << part);
-#ifdef CDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("open complete\n");
-#endif /*CDDEBUG*/
- cd->flags |= CDVALID;
+ /*
+ * Check that the partition exists
+ */
+ if ((cd->disklabel.d_partitions[part].p_fstype == FS_UNUSED)
+ && (part != RAW_PART)) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("part %d type UNUSED\n", part));
+ errcode = ENXIO;
+ goto bad;
}
- else
- {
-#ifdef CDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("part %d type UNUSED\n",part);
-#endif /*CDDEBUG*/
- cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT);
- return(ENXIO);
+ cd->partflags[part] |= CDOPEN;
+ cd->openparts |= (1 << part);
+ SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n"));
+ sc_link->flags |= SDEV_MEDIA_LOADED;
+ return (0);
+ bad:
+
+ /*
+ * if we would have been the only open
+ * then leave things back as they were
+ */
+ if (!(cd->openparts)) {
+ sc_link->flags &= ~SDEV_OPEN;
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
}
- return(0);
+ return (errcode);
}
-/*******************************************************\
-* Get ownership of a scsi_xfer structure *
-* If need be, sleep on it, until it comes free *
-\*******************************************************/
-struct scsi_xfer *cd_get_xs(unit,flags)
-int flags;
-int unit;
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval
+cdclose(dev)
+ dev_t dev;
{
- struct scsi_xfer *xs;
+ u_int8 unit, part;
+ u_int32 old_priority;
struct cd_data *cd;
- int s;
-
- cd = cd_driver->cd_data[unit];
- if(flags & (SCSI_NOSLEEP | SCSI_NOMASK))
- {
- if (xs = cd->free_xfer)
- {
- cd->free_xfer = xs->next;
- xs->flags = 0;
- }
- }
- else
- {
- s = SPLCD();
- while (!(xs = cd->free_xfer))
- {
- cd->xfer_block_wait++; /* someone waiting! */
- sleep((caddr_t)&cd->free_xfer, PRIBIO+1);
- cd->xfer_block_wait--;
- }
- cd->free_xfer = xs->next;
- splx(s);
- xs->flags = 0;
- }
- return(xs);
-}
+ struct scsi_link *sc_link;
-/*******************************************************\
-* Free a scsi_xfer, wake processes waiting for it *
-\*******************************************************/
-cd_free_xs(unit,xs,flags)
-struct scsi_xfer *xs;
-int unit;
-int flags;
-{
- struct cd_data *cd;
- int s;
-
- cd = cd_driver->cd_data[unit];
- if(flags & SCSI_NOMASK)
- {
- if (cd->xfer_block_wait)
- {
- printf("cd%d: doing a wakeup from NOMASK mode\n", unit);
- wakeup((caddr_t)&cd->free_xfer);
- }
- xs->next = cd->free_xfer;
- cd->free_xfer = xs;
- }
- else
- {
- s = SPLCD();
- if (cd->xfer_block_wait)
- wakeup((caddr_t)&cd->free_xfer);
- xs->next = cd->free_xfer;
- cd->free_xfer = xs;
- splx(s);
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ cd = cd_driver.cd_data[unit];
+ sc_link = cd->sc_link;
+ SC_DEBUG(sc_link, SDEV_DB2, ("cd%d: closing part %d\n", unit, part));
+ cd->partflags[part] &= ~CDOPEN;
+ cd->openparts &= ~(1 << part);
+
+ /*
+ * If we were the last open of the entire device, release it.
+ */
+ if (!(cd->openparts)) {
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
+ cd->sc_link->flags &= ~SDEV_OPEN;
}
+ return (0);
}
-/*******************************************************\
-* trim the size of the transfer if needed, *
-* called by physio *
-* basically the smaller of our max and the scsi driver's*
-* minphys (note we have no max ourselves) *
-\*******************************************************/
-/* Trim buffer length if buffer-size is bigger than page size */
-void cdminphys(bp)
-struct buf *bp;
+/*
+ * trim the size of the transfer if needed,
+ * called by physio
+ * basically the smaller of our max and the scsi driver's
+ * minphys (note we have no max ourselves)
+ *
+ * Trim buffer length if buffer-size is bigger than page size
+ */
+void
+cdminphys(bp)
+ struct buf *bp;
{
- (*(cd_driver->cd_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp);
+ (*(cd_driver.cd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
}
-/*******************************************************\
-* Actually translate the requested transfer into *
-* one the physical driver can understand *
-* The transfer is described by a buf and will include *
-* only one physical transfer. *
-\*******************************************************/
-
-int cdstrategy(bp)
-struct buf *bp;
+/*
+ * Actually translate the requested transfer into one the physical driver can
+ * understand. The transfer is described by a buf and will include only one
+ * physical transfer.
+ */
+errval
+cdstrategy(bp)
+ struct buf *bp;
{
- struct buf *dp;
- unsigned int opri;
- struct cd_data *cd;
- int unit;
+ struct buf *dp;
+ u_int32 opri;
+ u_int32 unit = UNIT((bp->b_dev));
+ struct cd_data *cd = cd_driver.cd_data[unit];
cdstrats++;
- unit = UNIT((bp->b_dev));
- cd = cd_driver->cd_data[unit];
-#ifdef CDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("\ncdstrategy ");
- if(scsi_debug & SHOWREQUESTS) printf("cd%d: %d bytes @ blk%d\n",
- unit,bp->b_bcount,bp->b_blkno);
-#endif /*CDDEBUG*/
+ SC_DEBUG(cd->sc_link, SDEV_DB2, ("\ncdstrategy "));
+ SC_DEBUG(cd->sc_link, SDEV_DB1, ("cd%d: %d bytes @ blk%d\n",
+ unit, bp->b_bcount, bp->b_blkno));
cdminphys(bp);
- /*******************************************************\
- * If the device has been made invalid, error out *
- * maybe the media changed *
- \*******************************************************/
- if(!(cd->flags & CDVALID))
- {
+ /*
+ * If the device has been made invalid, error out
+ * maybe the media changed
+ */
+ if (!(cd->sc_link->flags & SDEV_MEDIA_LOADED)) {
bp->b_error = EIO;
goto bad;
}
- /*******************************************************\
- * can't ever write to a CD *
- \*******************************************************/
+ /*
+ * can't ever write to a CD
+ */
if ((bp->b_flags & B_READ) == 0) {
bp->b_error = EROFS;
goto bad;
}
- /*******************************************************\
- * If it's a null transfer, return immediatly *
- \*******************************************************/
+ /*
+ * If it's a null transfer, return immediatly
+ */
if (bp->b_bcount == 0) {
goto done;
}
-
- /*******************************************************\
- * Decide which unit and partition we are talking about *
- \*******************************************************/
- if(PARTITION(bp->b_dev) != RAW_PART)
- {
- if (!(cd->flags & CDHAVELABEL))
- {
- bp->b_error = EIO;
- goto bad;
- }
+ /*
+ * Decide which unit and partition we are talking about
+ */
+ if (PARTITION(bp->b_dev) != RAW_PART) {
/*
* do bounds checking, adjust transfer. if error, process.
* if end of partition, just return
*/
- if (bounds_check_with_label(bp,&cd->disklabel,1) <= 0)
+ if (bounds_check_with_label(bp, &cd->disklabel, 1) <= 0)
goto done;
/* otherwise, process transfer request */
}
-
opri = SPLCD();
dp = &cd->buf_queue;
- /*******************************************************\
- * Place it in the queue of disk activities for this disk*
- \*******************************************************/
+ /*
+ * Place it in the queue of disk activities for this disk
+ */
disksort(dp, bp);
- /*******************************************************\
- * Tell the device to get going on the transfer if it's *
- * not doing anything, otherwise just wait for completion*
- \*******************************************************/
+ /*
+ * Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion
+ */
cdstart(unit);
splx(opri);
return;
-bad:
+ bad:
bp->b_flags |= B_ERROR;
-done:
+ done:
- /*******************************************************\
- * Correctly set the buf to indicate a completed xfer *
- \*******************************************************/
- bp->b_resid = bp->b_bcount;
+ /*
+ * Correctly set the buf to indicate a completed xfer
+ */
+ bp->b_resid = bp->b_bcount;
biodone(bp);
- return;
+ return (0);
}
-/***************************************************************\
-* cdstart looks to see if there is a buf waiting for the device *
-* and that the device is not already busy. If both are true, *
-* It deques the buf and creates a scsi command to perform the *
-* transfer in the buf. The transfer request will call cd_done *
-* on completion, which will in turn call this routine again *
-* so that the next queued transfer is performed. *
-* The bufs are queued by the strategy routine (cdstrategy) *
-* *
-* This routine is also called after other non-queued requests *
-* have been made of the scsi driver, to ensure that the queue *
-* continues to be drained. *
-* *
-* must be called at the correct (highish) spl level *
-\***************************************************************/
-/* cdstart() is called at SPLCD from cdstrategy and cd_done*/
+/*
+ * cdstart looks to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It deques the buf and creates a scsi command to perform the
+ * transfer in the buf. The transfer request will call scsi_done
+ * on completion, which will in turn call this routine again
+ * so that the next queued transfer is performed.
+ * The bufs are queued by the strategy routine (cdstrategy)
+ *
+ * This routine is also called after other non-queued requests
+ * have been made of the scsi driver, to ensure that the queue
+ * continues to be drained.
+ *
+ * must be called at the correct (highish) spl level
+ * cdstart() is called at SPLCD from cdstrategy and scsi_done
+ */
+void
cdstart(unit)
-int unit;
+ u_int32 unit;
{
- register struct buf *bp = 0;
- register struct buf *dp;
- struct scsi_xfer *xs;
- struct scsi_rw_big cmd;
- int blkno, nblk;
- struct cd_data *cd;
- struct partition *p ;
-
-#ifdef CDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("cdstart%d ",unit);
-#endif /*CDDEBUG*/
- cd = cd_driver->cd_data[unit];
- /*******************************************************\
- * See if there is a buf to do and we are not already *
- * doing one *
- \*******************************************************/
- if(!cd->free_xfer)
- {
- return; /* none for us, unit already underway */
+ register struct buf *bp = 0;
+ register struct buf *dp;
+ struct scsi_rw_big cmd;
+ u_int32 blkno, nblk;
+ struct partition *p;
+ struct cd_data *cd = cd_driver.cd_data[unit];
+ struct scsi_link *sc_link = cd->sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("cdstart%d ", unit));
+ /*
+ * See if there is a buf to do and we are not already
+ * doing one
+ */
+ if (!sc_link->opennings) {
+ return; /* no room for us, unit already underway */
}
-
- if(cd->xfer_block_wait) /* there is one, but a special waits */
- {
- return; /* give the special that's waiting a chance to run */
+ if (sc_link->flags & SDEV_WAITING) { /* is room, but a special waits */
+ return; /* give the special that's waiting a chance to run */
}
-
-
dp = &cd->buf_queue;
- if ((bp = dp->b_actf) != NULL) /* yes, an assign */
- {
+ if ((bp = dp->b_actf) != NULL) { /* yes, an assign */
dp->b_actf = bp->av_forw;
- }
- else
- {
+ } else {
return;
}
-
- xs=cd_get_xs(unit,0); /* ok we can grab it */
- xs->flags = INUSE; /* Now ours */
- /***************************************************************\
- * Should reject all queued entries if CDVALID is not true *
- \***************************************************************/
- if(!(cd->flags & CDVALID))
- {
- goto bad; /* no I/O.. media changed or something */
+ /*
+ * Should reject all queued entries if SDEV_MEDIA_LOADED is not true.
+ */
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ goto bad; /* no I/O.. media changed or something */
}
-
- /*******************************************************\
- * We have a buf, now we should move the data into *
- * a scsi_xfer definition and try start it *
- * *
- * First, translate the block to absolute *
- * and put it in terms of the logical blocksize of the *
- * device.. *
- * really a bit silly until we have real partitions, but.*
- \*******************************************************/
- blkno = bp->b_blkno / (cd->params.blksize/512);
- if(PARTITION(bp->b_dev) != RAW_PART)
- {
+ /*
+ * We have a buf, now we should make a command
+ *
+ * First, translate the block to absolute and put it in terms of the
+ * logical blocksize of the device. Really a bit silly until we have
+ * real partitions, but.
+ */
+ blkno = bp->b_blkno / (cd->params.blksize / 512);
+ if (PARTITION(bp->b_dev) != RAW_PART) {
p = cd->disklabel.d_partitions + PARTITION(bp->b_dev);
blkno += p->p_offset;
}
nblk = (bp->b_bcount + (cd->params.blksize - 1)) / (cd->params.blksize);
- /* what if something asks for 512 bytes not on a 2k boundary? *//*XXX*/
+ /* what if something asks for 512 bytes not on a 2k boundary? *//*XXX */
- /*******************************************************\
- * Fill out the scsi command *
- \*******************************************************/
+ /*
+ * Fill out the scsi command
+ */
bzero(&cmd, sizeof(cmd));
- cmd.op_code = READ_BIG;
- cmd.addr_3 = (blkno & 0xff000000) >> 24;
- cmd.addr_2 = (blkno & 0xff0000) >> 16;
- cmd.addr_1 = (blkno & 0xff00) >> 8;
- cmd.addr_0 = blkno & 0xff;
- cmd.length2 = (nblk & 0xff00) >> 8;
- cmd.length1 = (nblk & 0xff);
- /*******************************************************\
- * Fill out the scsi_xfer structure *
- * Note: we cannot sleep as we may be an interrupt *
- \*******************************************************/
- xs->flags |= SCSI_NOSLEEP;
- xs->adapter = cd->ctlr;
- xs->targ = cd->targ;
- xs->lu = cd->lu;
- xs->retries = CD_RETRIES;
- xs->timeout = 10000;/* 10000 millisecs for a disk !*/
- xs->cmd = (struct scsi_generic *)&cmd;
- xs->cmdlen = sizeof(cmd);
- xs->resid = bp->b_bcount;
- xs->when_done = cd_done;
- xs->done_arg = unit;
- xs->done_arg2 = (int)xs;
- xs->error = XS_NOERROR;
- xs->bp = bp;
- xs->data = (u_char *)bp->b_un.b_addr;
- xs->datalen = bp->b_bcount;
-
- /*******************************************************\
- * Pass all this info to the scsi driver. *
- \*******************************************************/
- if ( (*(cd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED)
- {
- printf("cd%d: oops not queued",unit);
- goto bad;
- }
- cdqueues++;
- return;
-bad: xs->error = XS_DRIVER_STUFFUP;
- cd_done(unit,xs);
-}
-
-/*******************************************************\
-* This routine is called by the scsi interrupt when *
-* the transfer is complete. (or failed) *
-\*******************************************************/
-int cd_done(unit,xs)
-int unit;
-struct scsi_xfer *xs;
-{
- struct buf *bp;
- int retval;
- struct cd_data *cd = cd_driver->cd_data[unit];
-
-#ifdef CDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("cd_done%d ",unit);
-#endif /*CDDEBUG*/
-#ifdef PARANOIA
- if (! (xs->flags & INUSE)) /* paranoia always pays off */
- panic("scsi_xfer not in use!");
-#endif /*PARANOIA*/
- if(!(bp = xs->bp))
- {
- wakeup(xs);
- return 0;
- }
- switch(xs->error)
- {
- case XS_NOERROR:
- bp->b_error = 0;
- bp->b_resid = 0;
- break;
-
- case XS_SENSE:
- retval = (cd_interpret_sense(unit,xs));
- if(retval)
- {
- bp->b_flags |= B_ERROR;
- bp->b_error = retval;
- }
- break;
-
- case XS_TIMEOUT:
- printf("cd%d timeout\n",unit);
-
- case XS_BUSY:
- /***********************************\
- * Just resubmit it straight back to *
- * the SCSI driver to try it again *
- \***********************************/
- if(xs->retries--)
- {
- xs->error = XS_NOERROR;
- xs->flags &= ~ITSDONE;
- if ((*(cd->sc_sw->scsi_cmd))(xs)
- == SUCCESSFULLY_QUEUED)
- { /* shhh! don't wake the job, ok? */
- /* don't tell cdstart either, */
- return 0;
- }
- /* xs->error is set by the scsi driver */
- } /* Fall through */
-
- case XS_DRIVER_STUFFUP:
- bp->b_flags |= B_ERROR;
+ cmd.op_code = READ_BIG;
+ cmd.addr_3 = (blkno & 0xff000000) >> 24;
+ cmd.addr_2 = (blkno & 0xff0000) >> 16;
+ cmd.addr_1 = (blkno & 0xff00) >> 8;
+ cmd.addr_0 = blkno & 0xff;
+ cmd.length2 = (nblk & 0xff00) >> 8;
+ cmd.length1 = (nblk & 0xff);
+
+ /*
+ * Call the routine that chats with the adapter.
+ * Note: we cannot sleep as we may be an interrupt
+ */
+ if (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &cmd,
+ sizeof(cmd),
+ (u_char *) bp->b_un.b_addr,
+ bp->b_bcount,
+ CDRETRIES,
+ 30000,
+ bp,
+ SCSI_NOSLEEP | ((bp->b_flags & B_READ) ?
+ SCSI_DATA_IN : SCSI_DATA_OUT))
+ != SUCCESSFULLY_QUEUED) {
+ bad:
+ printf("cd%d: oops not queued", unit);
bp->b_error = EIO;
- break;
- default:
- printf("cd%d: unknown error category from scsi driver\n"
- ,unit);
- }
- biodone(bp);
- cd_free_xs(unit,xs,0);
- cdstart(unit); /* If there's anything waiting.. do it */
- return 0;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ return;
+ }
+ cdqueues++;
}
-/*******************************************************\
-* Perform special action on behalf of the user *
-* Knows about the internals of this device *
-\*******************************************************/
+/*
+ * Perform special action on behalf of the user.
+ * Knows about the internals of this device
+ */
+errval
cdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
{
- int error = 0;
- unsigned int opri;
- unsigned char unit, part;
+ errval error = 0;
+ u_int32 opri;
+ u_int8 unit, part;
register struct cd_data *cd;
-
- /*******************************************************\
- * Find the device that the user is talking about *
- \*******************************************************/
+ /*
+ * Find the device that the user is talking about
+ */
unit = UNIT(dev);
part = PARTITION(dev);
- cd = cd_driver->cd_data[unit];
-#ifdef CDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("cdioctl%d ",unit);
-#endif /*CDDEBUG*/
-
- /*******************************************************\
- * If the device is not valid.. abandon ship *
- \*******************************************************/
- if (!(cd_driver->cd_data[unit]->flags & CDVALID))
- return(EIO);
- switch(cmd)
- {
+ cd = cd_driver.cd_data[unit];
+ SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%x ", cmd));
+
+ /*
+ * If the device is not valid.. abandon ship
+ */
+ if (!(cd->sc_link->flags & SDEV_MEDIA_LOADED))
+ return (EIO);
+ switch (cmd) {
case DIOCSBAD:
- error = EINVAL;
+ error = EINVAL;
break;
case DIOCGDINFO:
- *(struct disklabel *)addr = cd->disklabel;
+ *(struct disklabel *) addr = cd->disklabel;
break;
- case DIOCGPART:
- ((struct partinfo *)addr)->disklab = &cd->disklabel;
- ((struct partinfo *)addr)->part =
- &cd->disklabel.d_partitions[PARTITION(dev)];
- break;
-
- case DIOCWDINFO:
- case DIOCSDINFO:
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else
- error = setdisklabel(&cd->disklabel,
- (struct disklabel *)addr,
- /*(cd->flags & DKFL_BSDLABEL) ? cd->openparts : */0,
- 0);
- if (error == 0) {
- cd->flags |= CDHAVELABEL;
- }
- break;
+ case DIOCGPART:
+ ((struct partinfo *) addr)->disklab = &cd->disklabel;
+ ((struct partinfo *) addr)->part =
+ &cd->disklabel.d_partitions[PARTITION(dev)];
+ break;
+
+ /*
+ * a bit silly, but someone might want to test something on a
+ * section of cdrom.
+ */
+ case DIOCWDINFO:
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ error = setdisklabel(&cd->disklabel,
+ (struct disklabel *) addr,
+ 0,
+ 0);
+ if (error == 0)
+ break;
- case DIOCWLABEL:
- error = EBADF;
- break;
+ case DIOCWLABEL:
+ error = EBADF;
+ break;
case CDIOCPLAYTRACKS:
{
- struct ioc_play_track *args
- = (struct ioc_play_track *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_play_track *args
+ = (struct ioc_play_track *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
data.page.audio.flags &= ~CD_PA_SOTC;
data.page.audio.flags |= CD_PA_IMMED;
- if(error = cd_set_mode(unit,&data))
+ if (error = cd_set_mode(unit, &data))
break;
- return(cd_play_tracks(unit
- ,args->start_track
- ,args->start_index
- ,args->end_track
- ,args->end_index
- ));
+ return (cd_play_tracks(unit
+ ,args->start_track
+ ,args->start_index
+ ,args->end_track
+ ,args->end_index
+ ));
}
break;
case CDIOCPLAYMSF:
{
- struct ioc_play_msf *args
- = (struct ioc_play_msf *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_play_msf *args
+ = (struct ioc_play_msf *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
data.page.audio.flags &= ~CD_PA_SOTC;
data.page.audio.flags |= CD_PA_IMMED;
- if(error = cd_set_mode(unit,&data))
+ if (error = cd_set_mode(unit, &data))
break;
- return(cd_play_msf(unit
- ,args->start_m
- ,args->start_s
- ,args->start_f
- ,args->end_m
- ,args->end_s
- ,args->end_f
- ));
+ return (cd_play_msf(unit
+ ,args->start_m
+ ,args->start_s
+ ,args->start_f
+ ,args->end_m
+ ,args->end_s
+ ,args->end_f
+ ));
}
break;
case CDIOCPLAYBLOCKS:
{
- struct ioc_play_blocks *args
- = (struct ioc_play_blocks *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_play_blocks *args
+ = (struct ioc_play_blocks *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
data.page.audio.flags &= ~CD_PA_SOTC;
data.page.audio.flags |= CD_PA_IMMED;
- if(error = cd_set_mode(unit,&data))
+ if (error = cd_set_mode(unit, &data))
break;
- return(cd_play(unit,args->blk,args->len));
-
+ return (cd_play(unit, args->blk, args->len));
}
break;
case CDIOCREADSUBCHANNEL:
{
struct ioc_read_subchannel *args
- = (struct ioc_read_subchannel *)addr;
+ = (struct ioc_read_subchannel *) addr;
struct cd_sub_channel_info data;
- int len=args->data_len;
- if(len>sizeof(data)||
- len<sizeof(struct cd_sub_channel_header)) {
- error=EINVAL;
+ u_int32 len = args->data_len;
+ if (len > sizeof(data) ||
+ len < sizeof(struct cd_sub_channel_header)) {
+ error = EINVAL;
break;
}
- if(error = cd_read_subchannel(unit,args->address_format,
- args->data_format,args->track,&data,len)) {
+ if (error = cd_read_subchannel(unit, args->address_format,
+ args->data_format, args->track, &data, len)) {
break;
}
- len=MIN(len,((data.header.data_len[0]<<8)+data.header.data_len[1]+
- sizeof(struct cd_sub_channel_header)));
- if(copyout(&data,args->data,len)!=0) {
- error=EFAULT;
+ len = MIN(len, ((data.header.data_len[0] << 8) + data.header.data_len[1] +
+ sizeof(struct cd_sub_channel_header)));
+ if (copyout(&data, args->data, len) != 0) {
+ error = EFAULT;
}
}
break;
case CDIOREADTOCHEADER:
{
struct ioc_toc_header th;
- if( error = cd_read_toc(unit,0,0,&th,sizeof(th)))
+ if (error = cd_read_toc(unit, 0, 0, &th, sizeof(th)))
break;
- th.len=(th.len&0xff)<<8+((th.len>>8)&0xff);
- bcopy(&th,addr,sizeof(th));
+ th.len = (th.len & 0xff) << 8 + ((th.len >> 8) & 0xff);
+ bcopy(&th, addr, sizeof(th));
}
break;
case CDIOREADTOCENTRYS:
{
- struct ioc_read_toc_entry *te=
- (struct ioc_read_toc_entry *)addr;
+ struct ioc_read_toc_entry *te =
+ (struct ioc_read_toc_entry *) addr;
struct cd_toc_entry data[65];
struct ioc_toc_header *th;
- int len=te->data_len;
- th=(struct ioc_toc_header *)data;
-
- if(len>sizeof(data) || len<sizeof(struct cd_toc_entry)) {
- error=EINVAL;
- break;
- }
- if(error = cd_read_toc(unit,te->address_format,
- te->starting_track,
- data,
- len))
+ u_int32 len = te->data_len;
+ th = (struct ioc_toc_header *) data;
+
+ if (len > sizeof(data) || len < sizeof(struct cd_toc_entry)) {
+ error = EINVAL;
break;
- len=MIN(len,((((th->len&0xff)<<8)+((th->len>>8)))+
- sizeof(*th)));
- if(copyout(th,te->data,len)!=0) {
- error=EFAULT;
}
-
+ if (error = cd_read_toc(unit, te->address_format,
+ te->starting_track,
+ data,
+ len))
+ break;
+ len = MIN(len, ((((th->len & 0xff) << 8) + ((th->len >> 8))) +
+ sizeof(*th)));
+ if (copyout(th, te->data, len) != 0) {
+ error = EFAULT;
+ }
}
break;
case CDIOCSETPATCH:
{
- struct ioc_patch *arg = (struct ioc_patch *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_patch *arg = (struct ioc_patch *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
data.page.audio.port[LEFT_PORT].channels = arg->patch[0];
data.page.audio.port[RIGHT_PORT].channels = arg->patch[1];
data.page.audio.port[2].channels = arg->patch[2];
data.page.audio.port[3].channels = arg->patch[3];
- if(error = cd_set_mode(unit,&data))
- break;
+ if (error = cd_set_mode(unit, &data))
+ break; /* eh? */
}
break;
case CDIOCGETVOL:
{
- struct ioc_vol *arg = (struct ioc_vol *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume;
arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume;
@@ -941,148 +740,146 @@ cdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
break;
case CDIOCSETVOL:
{
- struct ioc_vol *arg = (struct ioc_vol *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT];
data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT];
data.page.audio.port[2].volume = arg->vol[2];
data.page.audio.port[3].volume = arg->vol[3];
- if(error = cd_set_mode(unit,&data))
+ if (error = cd_set_mode(unit, &data))
break;
}
break;
case CDIOCSETMONO:
{
- struct ioc_vol *arg = (struct ioc_vol *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
- data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL|4|8;
- data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL;
+ data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL | 4 | 8;
+ data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL;
data.page.audio.port[2].channels = 0;
data.page.audio.port[3].channels = 0;
- if(error = cd_set_mode(unit,&data))
+ if (error = cd_set_mode(unit, &data))
break;
}
break;
case CDIOCSETSTERIO:
{
- struct ioc_vol *arg = (struct ioc_vol *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
data.page.audio.port[2].channels = 0;
data.page.audio.port[3].channels = 0;
- if(error = cd_set_mode(unit,&data))
+ if (error = cd_set_mode(unit, &data))
break;
}
break;
case CDIOCSETMUTE:
{
- struct ioc_vol *arg = (struct ioc_vol *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
data.page.audio.port[LEFT_PORT].channels = 0;
data.page.audio.port[RIGHT_PORT].channels = 0;
data.page.audio.port[2].channels = 0;
data.page.audio.port[3].channels = 0;
- if(error = cd_set_mode(unit,&data))
+ if (error = cd_set_mode(unit, &data))
break;
}
break;
case CDIOCSETLEFT:
{
- struct ioc_vol *arg = (struct ioc_vol *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL;
data.page.audio.port[2].channels = 0;
data.page.audio.port[3].channels = 0;
- if(error = cd_set_mode(unit,&data))
+ if (error = cd_set_mode(unit, &data))
break;
}
break;
case CDIOCSETRIGHT:
{
- struct ioc_vol *arg = (struct ioc_vol *)addr;
- struct cd_mode_data data;
- if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
break;
data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
data.page.audio.port[2].channels = 0;
data.page.audio.port[3].channels = 0;
- if(error = cd_set_mode(unit,&data))
+ if (error = cd_set_mode(unit, &data))
break;
}
break;
case CDIOCRESUME:
- error = cd_pause(unit,1);
+ error = cd_pause(unit, 1);
break;
case CDIOCPAUSE:
- error = cd_pause(unit,0);
+ error = cd_pause(unit, 0);
break;
case CDIOCSTART:
- error = cd_start_unit(unit,part,CD_START);
+ error = scsi_start_unit(cd->sc_link, 0);
break;
case CDIOCSTOP:
- error = cd_start_unit(unit,part,CD_STOP);
+ error = scsi_start_unit(cd->sc_link, 0);
break;
case CDIOCEJECT:
- error = cd_start_unit(unit,part,CD_EJECT);
+ error = scsi_start_unit(cd->sc_link, 0);
break;
case CDIOCSETDEBUG:
- scsi_debug = 0xfff; cd_debug = 0xfff;
+ cd->sc_link->flags |= (SDEV_DB1 | SDEV_DB2);
break;
case CDIOCCLRDEBUG:
- scsi_debug = 0; cd_debug = 0;
+ cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2);
break;
case CDIOCRESET:
- return(cd_reset(unit));
+ return (cd_reset(unit));
break;
default:
- error = ENOTTY;
+ if(part == RAW_PART)
+ error = scsi_do_ioctl(cd->sc_link,cmd,addr,flag);
+ else
+ error = ENOTTY;
break;
}
return (error);
}
-
-/*******************************************************\
-* Load the label information on the named device *
-* *
-* EVENTUALLY take information about different *
-* data tracks from the TOC and put it in the disklabel *
-\*******************************************************/
-int cdgetdisklabel(unit)
-unsigned char unit;
+/*
+ * Load the label information on the named device
+ * Actually fabricate a disklabel
+ *
+ * EVENTUALLY take information about different
+ * data tracks from the TOC and put it in the disklabel
+ */
+errval
+cdgetdisklabel(unit)
+ u_int8 unit;
{
- /*unsigned int n, m;*/
- char *errstring;
- struct dos_partition *dos_partition_p;
+ /*unsigned int n, m; */
+ char *errstring;
struct cd_data *cd;
- cd = cd_driver->cd_data[unit];
- /*******************************************************\
- * If the info is already loaded, use it *
- \*******************************************************/
- if(cd->flags & CDHAVELABEL) return;
-
- bzero(&cd->disklabel,sizeof(struct disklabel));
- /*******************************************************\
- * make partition 3 the whole disk in case of failure *
- * then get pdinfo *
- \*******************************************************/
- strncpy(cd->disklabel.d_typename,"scsi cd_rom",16);
- strncpy(cd->disklabel.d_packname,"ficticious",16);
- cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */
+ cd = cd_driver.cd_data[unit];
+
+ bzero(&cd->disklabel, sizeof(struct disklabel));
+ /*
+ * make partition 0 the whole disk
+ */
+ strncpy(cd->disklabel.d_typename, "scsi cd_rom", 16);
+ strncpy(cd->disklabel.d_packname, "ficticious", 16);
+ cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */
cd->disklabel.d_nsectors = 100;
cd->disklabel.d_ntracks = 1;
cd->disklabel.d_ncylinders = (cd->params.disksize / 100) + 1;
@@ -1092,129 +889,118 @@ unsigned char unit;
cd->disklabel.d_interleave = 1;
cd->disklabel.d_flags = D_REMOVABLE;
+ /*
+ * remember that comparisons with the partition are done
+ * assuming the blocks are 512 bytes so fudge it.
+ */
cd->disklabel.d_npartitions = 1;
- cd->disklabel.d_partitions[0].p_offset = 0;
- cd->disklabel.d_partitions[0].p_size
- = cd->params.disksize * (cd->params.blksize / 512);
- cd->disklabel.d_partitions[0].p_fstype = 9;
+ cd->disklabel.d_partitions[0].p_offset = 0;
+ cd->disklabel.d_partitions[0].p_size
+ = cd->params.disksize * (cd->params.blksize / 512);
+ cd->disklabel.d_partitions[0].p_fstype = 9;
cd->disklabel.d_magic = DISKMAGIC;
cd->disklabel.d_magic2 = DISKMAGIC;
cd->disklabel.d_checksum = dkcksum(&(cd->disklabel));
- /*******************************************************\
- * Signal to other users and routines that we now have a *
- * disklabel that represents the media (maybe) *
- \*******************************************************/
- cd->flags |= CDHAVELABEL;
- return(ESUCCESS);
-}
-
-/*******************************************************\
-* Get scsi driver to send a "are you ready" command *
-\*******************************************************/
-cd_test_ready(unit,flags)
-int unit,flags;
-{
- struct scsi_test_unit_ready scsi_cmd;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = TEST_UNIT_READY;
-
- return (cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 100000,
- NULL,
- flags));
+ /*
+ * Signal to other users and routines that we now have a
+ * disklabel that represents the media (maybe)
+ */
+ return (ESUCCESS);
}
-
-/*******************************************************\
-* Find out form the device what it's capacity is *
-\*******************************************************/
+/*
+ * Find out from the device what it's capacity is
+ */
+u_int32
cd_size(unit, flags)
{
- struct scsi_read_cd_cap_data rdcap;
- struct scsi_read_cd_capacity scsi_cmd;
- int size;
- int blksize;
-
- /*******************************************************\
- * make up a scsi command and ask the scsi driver to do *
- * it for you. *
- \*******************************************************/
+ struct scsi_read_cd_cap_data rdcap;
+ struct scsi_read_cd_capacity scsi_cmd;
+ u_int32 size;
+ u_int32 blksize;
+ struct cd_data *cd = cd_driver.cd_data[unit];
+
+ /*
+ * make up a scsi command and ask the scsi driver to do
+ * it for you.
+ */
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = READ_CD_CAPACITY;
- /*******************************************************\
- * If the command works, interpret the result as a 4 byte*
- * number of blocks *
- \*******************************************************/
- if (cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- &rdcap,
- sizeof(rdcap),
- 2000,
- NULL,
- flags) != 0)
- {
+ /*
+ * If the command works, interpret the result as a 4 byte
+ * number of blocks and a blocksize
+ */
+ if (scsi_scsi_cmd(cd->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & rdcap,
+ sizeof(rdcap),
+ CDRETRIES,
+ 20000, /* might be a disk-changer */
+ NULL,
+ SCSI_DATA_IN | flags) != 0) {
printf("cd%d: could not get size\n", unit);
- return(0);
+ return (0);
} else {
- size = rdcap.addr_0 + 1 ;
+ size = rdcap.addr_0 + 1;
size += rdcap.addr_1 << 8;
size += rdcap.addr_2 << 16;
size += rdcap.addr_3 << 24;
- blksize = rdcap.length_0 ;
+ blksize = rdcap.length_0;
blksize += rdcap.length_1 << 8;
blksize += rdcap.length_2 << 16;
blksize += rdcap.length_3 << 24;
}
-#ifdef CDDEBUG
- if(cd_debug)printf("cd%d: %d %d byte blocks\n",unit,size,blksize);
-#endif /*CDDEBUG*/
- cd_driver->cd_data[unit]->params.disksize = size;
- cd_driver->cd_data[unit]->params.blksize = blksize;
- return(size);
+ if (blksize < 512)
+ blksize = 2048; /* some drives lie ! */
+ if (size < 100)
+ size = 400000; /* ditto */
+ SC_DEBUG(cd->sc_link, SDEV_DB3, ("cd%d: %d %d byte blocks\n"
+ ,unit, size, blksize));
+ cd->params.disksize = size;
+ cd->params.blksize = blksize;
+ return (size);
}
-
-
-/*******************************************************\
-* Get the requested page into the buffer given *
-\*******************************************************/
-cd_get_mode(unit,data,page)
-int unit;
-struct cd_mode_data *data;
-int page;
+
+/*
+ * Get the requested page into the buffer given
+ */
+errval
+cd_get_mode(unit, data, page)
+ u_int32 unit;
+ struct cd_mode_data *data;
+ u_int32 page;
{
struct scsi_mode_sense scsi_cmd;
- int retval;
+ errval retval;
bzero(&scsi_cmd, sizeof(scsi_cmd));
- bzero(data,sizeof(*data));
+ bzero(data, sizeof(*data));
scsi_cmd.op_code = MODE_SENSE;
scsi_cmd.page = page;
scsi_cmd.length = sizeof(*data) & 0xff;
- retval = cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- data,
- sizeof(*data),
- 20000, /* should be immed */
- NULL,
- 0);
+ retval = scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) data,
+ sizeof(*data),
+ CDRETRIES,
+ 20000, /* should be immed */
+ NULL,
+ SCSI_DATA_IN);
return (retval);
}
-/*******************************************************\
-* Get the requested page into the buffer given *
-\*******************************************************/
-cd_set_mode(unit,data)
-int unit;
-struct cd_mode_data *data;
+
+/*
+ * Get the requested page into the buffer given
+ */
+errval
+cd_set_mode(unit, data)
+ u_int32 unit;
+ struct cd_mode_data *data;
{
struct scsi_mode_select scsi_cmd;
@@ -1223,25 +1009,26 @@ struct cd_mode_data *data;
scsi_cmd.byte2 |= SMS_PF;
scsi_cmd.length = sizeof(*data) & 0xff;
data->header.data_length = 0;
- /*show_mem(data,sizeof(*data));*/
- return (cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- data,
- sizeof(*data),
- 20000, /* should be immed */
- NULL,
- 0)
- );
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) data,
+ sizeof(*data),
+ CDRETRIES,
+ 20000, /* should be immed */
+ NULL,
+ SCSI_DATA_OUT));
}
-/*******************************************************\
-* Get scsi driver to send a "start playing" command *
-\*******************************************************/
-cd_play(unit,blk,len)
-int unit,blk,len;
+
+/*
+ * Get scsi driver to send a "start playing" command
+ */
+errval
+cd_play(unit, blk, len)
+ u_int32 unit, blk, len;
{
struct scsi_play scsi_cmd;
- int retval;
+ errval retval;
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = PLAY;
@@ -1251,24 +1038,26 @@ int unit,blk,len;
scsi_cmd.blk_addr[3] = blk & 0xff;
scsi_cmd.xfer_len[0] = (len >> 8) & 0xff;
scsi_cmd.xfer_len[1] = len & 0xff;
- retval = cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 200000, /* should be immed */
- NULL,
- 0);
- return(retval);
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 200000, /* should be immed */
+ NULL,
+ 0));
}
-/*******************************************************\
-* Get scsi driver to send a "start playing" command *
-\*******************************************************/
-cd_play_big(unit,blk,len)
-int unit,blk,len;
+
+/*
+ * Get scsi driver to send a "start playing" command
+ */
+errval
+cd_play_big(unit, blk, len)
+ u_int32 unit, blk, len;
{
struct scsi_play_big scsi_cmd;
- int retval;
+ errval retval;
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = PLAY_BIG;
@@ -1280,24 +1069,26 @@ int unit,blk,len;
scsi_cmd.xfer_len[1] = (len >> 16) & 0xff;
scsi_cmd.xfer_len[2] = (len >> 8) & 0xff;
scsi_cmd.xfer_len[3] = len & 0xff;
- retval = cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 20000, /* should be immed */
- NULL,
- 0);
- return(retval);
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 20000, /* should be immed */
+ NULL,
+ 0));
}
-/*******************************************************\
-* Get scsi driver to send a "start playing" command *
-\*******************************************************/
-cd_play_tracks(unit,strack,sindex,etrack,eindex)
-int unit,strack,sindex,etrack,eindex;
+
+/*
+ * Get scsi driver to send a "start playing" command
+ */
+errval
+cd_play_tracks(unit, strack, sindex, etrack, eindex)
+ u_int32 unit, strack, sindex, etrack, eindex;
{
struct scsi_play_track scsi_cmd;
- int retval;
+ errval retval;
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = PLAY_TRACK;
@@ -1305,47 +1096,52 @@ int unit,strack,sindex,etrack,eindex;
scsi_cmd.start_index = sindex;
scsi_cmd.end_track = etrack;
scsi_cmd.end_index = eindex;
- retval = cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 20000, /* should be immed */
- NULL,
- 0);
- return(retval);
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 20000, /* should be immed */
+ NULL,
+ 0));
}
-/*******************************************************\
-* Get scsi driver to send a "play msf" command *
-\*******************************************************/
-cd_play_msf(unit,startm,starts,startf,endm,ends,endf)
-int unit,startm,starts,startf,endm,ends,endf;
+
+/*
+ * Get scsi driver to send a "play msf" command
+ */
+errval
+cd_play_msf(unit, startm, starts, startf, endm, ends, endf)
+ u_int32 unit, startm, starts, startf, endm, ends, endf;
{
struct scsi_play_msf scsi_cmd;
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = PLAY_MSF;
- scsi_cmd.start_m=startm;
- scsi_cmd.start_s=starts;
- scsi_cmd.start_f=startf;
- scsi_cmd.end_m=endm;
- scsi_cmd.end_s=ends;
- scsi_cmd.end_f=endf;
-
- return (cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 2000,
- NULL,
- 0));
+ scsi_cmd.start_m = startm;
+ scsi_cmd.start_s = starts;
+ scsi_cmd.start_f = startf;
+ scsi_cmd.end_m = endm;
+ scsi_cmd.end_s = ends;
+ scsi_cmd.end_f = endf;
+
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 2000,
+ NULL,
+ 0));
}
-/*******************************************************\
-* Get scsi driver to send a "start up" command *
-\*******************************************************/
-cd_pause(unit,go)
-int unit,go;
+
+/*
+ * Get scsi driver to send a "start up" command
+ */
+errval
+cd_pause(unit, go)
+ u_int32 unit, go;
{
struct scsi_pause scsi_cmd;
@@ -1353,534 +1149,132 @@ int unit,go;
scsi_cmd.op_code = PAUSE;
scsi_cmd.resume = go;
- return (cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 2000,
- NULL,
- 0));
-}
-/*******************************************************\
-* Get scsi driver to send a "RESET" command *
-\*******************************************************/
-cd_reset(unit)
-int unit;
-{
- return(cd_scsi_cmd(unit,
- 0,
- 0,
- 0,
- 0,
- 2000,
- NULL,
- SCSI_RESET));
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 2000,
+ NULL,
+ 0));
}
-/*******************************************************\
-* Get scsi driver to send a "start up" command *
-\*******************************************************/
-cd_start_unit(unit,part,type)
-{
- struct scsi_start_stop scsi_cmd;
- struct cd_data *cd = cd_driver->cd_data[unit];
- if(type==CD_EJECT
- /*&& (cd->openparts == 0)*/)/* trouble is WE have it open *//*XXX*/
- {
- cd_prevent_unit(unit,PR_ALLOW,0);
- }
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = START_STOP;
- scsi_cmd.how |= (type==CD_START)?SSS_START:0;
- scsi_cmd.how |= (type==CD_EJECT)?SSS_LOEJ:0;
-
- if (cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 2000,
- NULL,
- 0) != 0) {
- return(ENXIO);
- } else
- return(0);
-}
-/*******************************************************\
-* Prevent or allow the user to remove the disk *
-\*******************************************************/
-cd_prevent_unit(unit,type,flags)
-int unit,type,flags;
+/*
+ * Get scsi driver to send a "RESET" command
+ */
+errval
+cd_reset(unit)
+ u_int32 unit;
{
- struct scsi_prevent scsi_cmd;
- struct cd_data *cd = cd_driver->cd_data[unit];
-
- if(type==PR_PREVENT
- || ( type==PR_ALLOW && cd->openparts == 0 ))/*XXX*/
- {
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = PREVENT_ALLOW;
- scsi_cmd.how = type;
- if (cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(struct scsi_prevent),
- 0,
- 0,
- 5000,
- NULL,
- 0) != 0)
- {
- if(!(flags & SCSI_SILENT))
- printf("cd%d: cannot prevent/allow\n", unit);
- return(0);
- }
- }
- return(1);
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ 0,
+ 0,
+ 0,
+ 0,
+ CDRETRIES,
+ 2000,
+ NULL,
+ SCSI_RESET));
}
-/******************************************************\
-* Read Subchannel *
-\******************************************************/
-
-cd_read_subchannel(unit,mode,format,track,data,len)
-int unit,mode,format,len;
-struct cd_sub_channel_info *data;
+/*
+ * Read subchannel
+ */
+errval
+cd_read_subchannel(unit, mode, format, track, data, len)
+ u_int32 unit, mode, format, len;
+ struct cd_sub_channel_info *data;
{
struct scsi_read_subchannel scsi_cmd;
- int error;
+ errval error;
- bzero(&scsi_cmd,sizeof(scsi_cmd));
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code=READ_SUBCHANNEL;
- if(mode==CD_MSF_FORMAT)
+ scsi_cmd.op_code = READ_SUBCHANNEL;
+ if (mode == CD_MSF_FORMAT)
scsi_cmd.byte2 |= CD_MSF;
- scsi_cmd.byte3=SRS_SUBQ;
- scsi_cmd.subchan_format=format;
- scsi_cmd.track=track;
- scsi_cmd.data_len[0]=(len)>>8;
- scsi_cmd.data_len[1]=(len)&0xff;
- return cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(struct scsi_read_subchannel),
- data,
+ scsi_cmd.byte3 = SRS_SUBQ;
+ scsi_cmd.subchan_format = format;
+ scsi_cmd.track = track;
+ scsi_cmd.data_len[0] = (len) >> 8;
+ scsi_cmd.data_len[1] = (len) & 0xff;
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(struct scsi_read_subchannel),
+ (u_char *) data,
len,
+ CDRETRIES,
5000,
NULL,
- 0);
+ SCSI_DATA_IN));
}
-/*******************************************************\
-* Read Table of contents *
-\*******************************************************/
-cd_read_toc(unit,mode,start,data,len)
-int unit,mode,start,len;
-struct cd_toc_entry *data;
+/*
+ * Read table of contents
+ */
+errval
+cd_read_toc(unit, mode, start, data, len)
+ u_int32 unit, mode, start, len;
+ struct cd_toc_entry *data;
{
struct scsi_read_toc scsi_cmd;
- int error;
- int ntoc;
-
- bzero(&scsi_cmd,sizeof(scsi_cmd));
+ errval error;
+ u_int32 ntoc;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
/*if(len!=sizeof(struct ioc_toc_header))
- ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry);
- else*/
- ntoc=len;
-
- scsi_cmd.op_code=READ_TOC;
- if(mode==CD_MSF_FORMAT)
- scsi_cmd.byte2 |= CD_MSF;
- scsi_cmd.from_track=start;
- scsi_cmd.data_len[0]=(ntoc)>>8;
- scsi_cmd.data_len[1]=(ntoc)&0xff;
- return cd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(struct scsi_read_toc),
- data,
- len,
- 5000,
+ * ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry);
+ * else */
+ ntoc = len;
+
+ scsi_cmd.op_code = READ_TOC;
+ if (mode == CD_MSF_FORMAT)
+ scsi_cmd.byte2 |= CD_MSF;
+ scsi_cmd.from_track = start;
+ scsi_cmd.data_len[0] = (ntoc) >> 8;
+ scsi_cmd.data_len[1] = (ntoc) & 0xff;
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(struct scsi_read_toc),
+ (u_char *) data,
+ len,
+ CDRETRIES,
+ 5000,
NULL,
- 0);
+ SCSI_DATA_IN));
}
-
#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
-/*******************************************************\
-* Get the scsi driver to send a full inquiry to the *
-* device and use the results to fill out the disk *
-* parameter structure. *
-\*******************************************************/
-
-int cd_get_parms(unit, flags)
-{
- struct cd_data *cd = cd_driver->cd_data[unit];
-
- /*******************************************************\
- * First check if we have it all loaded *
- \*******************************************************/
- if(cd->flags & CDVALID) return(0);
- /*******************************************************\
- * give a number of sectors so that sec * trks * cyls *
- * is <= disk_size *
- \*******************************************************/
- if(cd_size(unit, flags))
- {
- cd->flags |= CDVALID;
- return(0);
- }
- else
- {
- return(ENXIO);
- }
-}
-
-/*******************************************************\
-* close the device.. only called if we are the LAST *
-* occurence of an open device *
-\*******************************************************/
-cdclose(dev)
-dev_t dev;
-{
- unsigned char unit, part;
- unsigned int old_priority;
-
- unit = UNIT(dev);
- part = PARTITION(dev);
-#ifdef CDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("cd%d: closing part %d\n",unit,part);
-#endif
- cd_driver->cd_data[unit]->partflags[part] &= ~CDOPEN;
- cd_driver->cd_data[unit]->openparts &= ~(1 << part);
- cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT);
- return(0);
-}
-
-/*******************************************************\
-* ask the scsi driver to perform a command for us. *
-* Call it through the switch table, and tell it which *
-* sub-unit we want, and what target and lu we wish to *
-* talk to. Also tell it where to find the command *
-* how long int is. *
-* Also tell it where to read/write the data, and how *
-* long the data is supposed to be *
-\*******************************************************/
-int cd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags)
-
-int unit,flags;
-struct scsi_generic *scsi_cmd;
-int cmdlen;
-int timeout;
-u_char *data_addr;
-int datalen;
-struct buf *bp;
+/*
+ * Get the scsi driver to send a full inquiry to the device and use the
+ * results to fill out the disk parameter structure.
+ */
+errval
+cd_get_parms(unit, flags)
{
- struct scsi_xfer *xs;
- int retval;
- int s;
- struct cd_data *cd = cd_driver->cd_data[unit];
-
-#ifdef CDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("\ncd_scsi_cmd%d ",unit);
-#endif /*CDDEBUG*/
-#ifdef PARANOID
- if(!(cd->sc_sw)) /* If we have a scsi driver */
- {
- /* !? how'd we GET here? */
- panic("attempt to run bad cd device");
- }
-#endif /*PARANOID*/
- xs = cd_get_xs(unit,flags); /* should wait unless booting */
- if(!xs)
- {
- printf("cd%d: scsi_cmd controller busy"
- " (this should never happen)\n",unit);
- return(EBUSY);
- }
- xs->flags |= INUSE;
- /*******************************************************\
- * Fill out the scsi_xfer structure *
- \*******************************************************/
- xs->flags |= flags;
- xs->adapter = cd->ctlr;
- xs->targ = cd->targ;
- xs->lu = cd->lu;
- xs->retries = CD_RETRIES;
- xs->timeout = timeout;
- xs->cmd = scsi_cmd;
- xs->cmdlen = cmdlen;
- xs->data = data_addr;
- xs->datalen = datalen;
- xs->resid = datalen;
- xs->when_done = (flags & SCSI_NOMASK)
- ?(int (*)())0
- :cd_done;
- xs->done_arg = unit;
- xs->done_arg2 = (int)xs;
- xs->bp = bp;
-retry: xs->error = XS_NOERROR;
- /*******************************************************\
- * Do the transfer. If we are polling we will return: *
- * COMPLETE, Was poll, and cd_done has been called *
- * HAD_ERROR, Was poll and an error was encountered *
- * TRY_AGAIN_LATER, Adapter short resources, try again *
- * *
- * if under full steam (interrupts) it will return: *
- * SUCCESSFULLY_QUEUED, will do a wakeup when complete *
- * HAD_ERROR, had an erro before it could queue *
- * TRY_AGAIN_LATER, (as for polling) *
- * After the wakeup, we must still check if it succeeded *
- * *
- * If we have a bp however, all the error proccessing *
- * and the buffer code both expect us to return straight *
- * to them, so as soon as the command is queued, return *
- \*******************************************************/
- retval = (*(cd->sc_sw->scsi_cmd))(xs);
- if(bp) return retval; /* will sleep (or not) elsewhere */
-
- /*******************************************************\
- * Only here for non I/O cmds. It's cheaper to process *
- * the error status here than at interrupt time so *
- * sd_done will have done nothing except wake us up. *
- \*******************************************************/
- switch(retval)
- {
- case SUCCESSFULLY_QUEUED:
- s = splbio();
- while(!(xs->flags & ITSDONE))
- sleep(xs,PRIBIO+1);
- splx(s);
- /* Fall through to check the result */
-
- case HAD_ERROR:
- switch(xs->error)
- {
- case XS_NOERROR: /* usually this one */
- retval = ESUCCESS;
- break;
-
- case XS_SENSE:
- retval = (cd_interpret_sense(unit,xs));
- break;
- case XS_BUSY:
- /* should sleep here 1 sec */
- /* fall through */
- case XS_TIMEOUT:
- if(xs->retries-- )
- {
- xs->flags &= ~ITSDONE;
- goto retry;
- }
- /* fall through */
- case XS_DRIVER_STUFFUP:
- retval = EIO;
- break;
- default:
- retval = EIO;
- printf("cd%d: unknown error category from scsi driver\n"
- ,unit);
- }
- break;
- case COMPLETE:
- retval = ESUCCESS;
- break;
+ struct cd_data *cd = cd_driver.cd_data[unit];
- case TRY_AGAIN_LATER:
- if(xs->retries-- )
- {
- if(tsleep( 0,PRIBIO + 2,"retry",hz * 2))
- {
- xs->flags &= ~ITSDONE;
- goto retry;
- }
- }
- /* fall through */
- default:
- retval = EIO;
- }
-
- /*******************************************************\
- * we have finished doing the command, free the struct *
- * and check if anyone else needs it *
- \*******************************************************/
- cd_free_xs(unit,xs,flags);
- cdstart(unit); /* check if anything is waiting for the xs */
- return(retval);
-}
-/***************************************************************\
-* Look at the returned sense and act on the error and detirmine *
-* The unix error number to pass back... (0 = report no error) *
-\***************************************************************/
-
-int cd_interpret_sense(unit,xs)
-int unit;
-struct scsi_xfer *xs;
-{
- struct scsi_sense_data *sense;
- int key;
- int silent;
- int info;
- struct cd_data *cd = cd_driver->cd_data[unit];
-
- static char *error_mes[] = { "soft error (corrected)",
- "not ready", "medium error",
- "non-media hardware failure", "illegal request",
- "unit attention", "readonly device",
- "no data found", "vendor unique",
- "copy aborted", "command aborted",
- "search returned equal", "volume overflow",
- "verify miscompare", "unknown error key"
- };
-
- /***************************************************************\
- * If the flags say errs are ok, then always return ok. *
- \***************************************************************/
- if (xs->flags & SCSI_ERR_OK) return(ESUCCESS);
- silent = (xs->flags & SCSI_SILENT);
-
- sense = &(xs->sense);
-#ifdef CDDEBUG
- if(cd_debug)
- {
- int count = 0;
- printf("code%x valid%x\n"
- ,sense->error_code & SSD_ERRCODE
- ,sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
- printf("seg%x key%x ili%x eom%x fmark%x\n"
- ,sense->ext.extended.segment
- ,sense->ext.extended.flags & SSD_KEY
- ,sense->ext.extended.flags & SSD_ILI ? 1 : 0
- ,sense->ext.extended.flags & SSD_EOM ? 1 : 0
- ,sense->ext.extended.flags & SSD_FILEMARK ? 1 : 0);
- printf("info: %x %x %x %x followed by %d extra bytes\n"
- ,sense->ext.extended.info[0]
- ,sense->ext.extended.info[1]
- ,sense->ext.extended.info[2]
- ,sense->ext.extended.info[3]
- ,sense->ext.extended.extra_len);
- printf("extra: ");
- while(count < sense->ext.extended.extra_len)
- {
- printf ("%x ",sense->ext.extended.extra_bytes[count++]);
- }
- printf("\n");
- }
-#endif /*CDDEBUG*/
- switch(sense->error_code & SSD_ERRCODE)
- {
- /***************************************************************\
- * If it's code 70, use the extended stuff and interpret the key *
- \***************************************************************/
- case 0x71:/* delayed error */
- printf("cd%d: DELAYED ERROR, key = 0x%x\n",unit,key);
- case 0x70:
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- info = ntohl(*((long *)sense->ext.extended.info));
- }
- else
- {
- info = 0;
- }
-
- key=sense->ext.extended.flags & SSD_KEY;
-
- if (!silent)
- {
- printf("cd%d: %s", unit, error_mes[key - 1]);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- switch (key)
- {
- case 0x2: /* NOT READY */
- case 0x5: /* ILLEGAL REQUEST */
- case 0x6: /* UNIT ATTENTION */
- case 0x7: /* DATA PROTECT */
- break;
- case 0x8: /* BLANK CHECK */
- printf(", requested size: %d (decimal)",
- info);
- break;
- default:
- printf(", info = %d (decimal)", info);
- }
- }
- printf("\n");
- }
-
- switch (key)
- {
- case 0x0: /* NO SENSE */
- case 0x1: /* RECOVERED ERROR */
- xs->resid = 0;
- case 0xc: /* EQUAL */
- return(ESUCCESS);
- case 0x2: /* NOT READY */
- cd->flags &= ~(CDVALID | CDHAVELABEL);
- return(ENODEV);
- case 0x5: /* ILLEGAL REQUEST */
- return(EINVAL);
- case 0x6: /* UNIT ATTENTION */
- cd->flags &= ~(CDVALID | CDHAVELABEL);
- if (cd->openparts)
- {
- return(EIO);
- }
- return(ESUCCESS);
- case 0x7: /* DATA PROTECT */
- return(EACCES);
- case 0xd: /* VOLUME OVERFLOW */
- return(ENOSPC);
- case 0x8: /* BLANK CHECK */
- return(ESUCCESS);
- default:
- return(EIO);
- }
- /*******************************\
- * Not code 70, just report it *
- \*******************************/
- default:
- if(!silent)
- {
- printf("cd%d: error code %d", unit,
- sense->error_code & SSD_ERRCODE);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" at block no. %d (decimal)",
- (sense->ext.unextended.blockhi <<16)
- + (sense->ext.unextended.blockmed <<8)
- + (sense->ext.unextended.blocklow ));
- }
- printf("\n");
- }
- return(EIO);
+ /*
+ * First check if we have it all loaded
+ */
+ if (cd->sc_link->flags & SDEV_MEDIA_LOADED)
+ return (0);
+ /*
+ * give a number of sectors so that sec * trks * cyls
+ * is <= disk_size
+ */
+ if (cd_size(unit, flags)) {
+ cd->sc_link->flags |= SDEV_MEDIA_LOADED;
+ return (0);
+ } else {
+ return (ENXIO);
}
}
-
-
-
int
cdsize(dev_t dev)
{
return (-1);
}
-
-#if 0
-show_mem(address,num)
-unsigned char *address;
-int num;
-{
- int x,y;
- printf("------------------------------");
- for (y = 0; y<num; y += 1)
- {
- if(!(y % 16))
- printf("\n%03d: ",y);
- printf("%02x ",*address++);
- }
- printf("\n------------------------------\n");
-}
-#endif
diff --git a/sys/scsi/ch.c b/sys/scsi/ch.c
index a76d522..c403fe5 100644
--- a/sys/scsi/ch.c
+++ b/sys/scsi/ch.c
@@ -1,7 +1,8 @@
/*
- * Written by Julian Elischer (julian@tfs.com)
+ * Written by grefen@?????
+ * Based on scsi drivers by Julian Elischer (julian@tfs.com)
*
- * $Id$
+ * $Id: ch.c,v 2.2 93/10/16 00:58:30 julian Exp Locker: julian $
*/
#include <sys/types.h>
@@ -17,965 +18,464 @@
#include <sys/user.h>
#include <sys/chio.h>
-#if defined(OSF)
-#define SECSIZE 512
-#endif /* defined(OSF) */
-
#include <scsi/scsi_all.h>
#include <scsi/scsi_changer.h>
#include <scsi/scsiconf.h>
-
-struct scsi_xfer ch_scsi_xfer[NCH];
-int ch_xfer_block_wait[NCH];
-
+struct scsi_xfer ch_scsi_xfer[NCH];
+u_int32 ch_xfer_block_wait[NCH];
#define PAGESIZ 4096
#define STQSIZE 4
-#define CH_RETRIES 4
-
+#define CHRETRIES 2
#define MODE(z) ( (minor(z) & 0x0F) )
#define UNIT(z) ( (minor(z) >> 4) )
-#ifndef MACH
#define ESUCCESS 0
-#endif MACH
-int ch_info_valid[NCH]; /* the info about the device is valid */
-int ch_initialized[NCH] ;
-int ch_debug = 1;
+errval chattach();
-int chattach();
-int ch_done();
-struct ch_data
+/*
+ * This driver is so simple it uses all the default services
+ */
+struct scsi_device ch_switch =
{
- int flags;
- struct scsi_switch *sc_sw; /* address of scsi low level switch */
- int ctlr; /* so they know which one we want */
- int targ; /* our scsi target ID */
- int lu; /* out scsi lu */
- short chmo; /* Offset of first CHM */
- short chms; /* No. of CHM */
- short slots; /* No. of Storage Elements */
- short sloto; /* Offset of first SE */
- short imexs; /* No. of Import/Export Slots */
- short imexo; /* Offset of first IM/EX */
- short drives; /* No. of CTS */
- short driveo; /* Offset of first CTS */
- short rot; /* CHM can rotate */
- u_long op_matrix; /* possible opertaions */
- u_short lsterr; /* details of lasterror */
- u_char stor; /* posible Storage locations */
-}ch_data[NCH];
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ch",
+ 0,
+ 0, 0
+};
+
+struct ch_data {
+ u_int32 flags;
+ struct scsi_link *sc_link; /* all the inter level info */
+ u_int16 chmo; /* Offset of first CHM */
+ u_int16 chms; /* No. of CHM */
+ u_int16 slots; /* No. of Storage Elements */
+ u_int16 sloto; /* Offset of first SE */
+ u_int16 imexs; /* No. of Import/Export Slots */
+ u_int16 imexo; /* Offset of first IM/EX */
+ u_int16 drives; /* No. of CTS */
+ u_int16 driveo; /* Offset of first CTS */
+ u_int16 rot; /* CHM can rotate */
+ u_long op_matrix; /* possible opertaions */
+ u_int16 lsterr; /* details of lasterror */
+ u_char stor; /* posible Storage locations */
+ u_int32 initialized;
+} ch_data[NCH];
#define CH_OPEN 0x01
#define CH_KNOWN 0x02
-static int next_ch_unit = 0;
-/***********************************************************************\
-* The routine called by the low level scsi routine when it discovers *
-* A device suitable for this driver *
-\***********************************************************************/
+static u_int32 next_ch_unit = 0;
-int chattach(ctlr,targ,lu,scsi_switch)
-struct scsi_switch *scsi_switch;
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * a device suitable for this driver.
+ */
+errval
+chattach(sc_link)
+ struct scsi_link *sc_link;
{
- int unit,i,stat;
+ u_int32 unit, i, stat;
unsigned char *tbl;
- if(scsi_debug & PRINTROUTINES) printf("chattach: ");
- /*******************************************************\
- * Check we have the resources for another drive *
- \*******************************************************/
+ SC_DEBUG(sc_link, SDEV_DB2, ("chattach: "));
+ /*
+ * Check we have the resources for another drive
+ */
unit = next_ch_unit++;
- if( unit >= NCH)
- {
- printf("Too many scsi changers..(%d > %d) reconfigure kernel\n",(unit + 1),NCH);
- return(0);
- }
- /*******************************************************\
- * Store information needed to contact our base driver *
- \*******************************************************/
- ch_data[unit].sc_sw = scsi_switch;
- ch_data[unit].ctlr = ctlr;
- ch_data[unit].targ = targ;
- ch_data[unit].lu = lu;
-
- /*******************************************************\
- * Use the subdriver to request information regarding *
- * the drive. We cannot use interrupts yet, so the *
- * request must specify this. *
- \*******************************************************/
- if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/)))
- {
- printf("ch%d: scsi changer, %d slot(s) %d drive(s) %d arm(s) %d i/e-slot(s)\n",
- unit, ch_data[unit].slots, ch_data[unit].drives, ch_data[unit].chms, ch_data[unit].imexs);
- stat=CH_KNOWN;
+ if (unit >= NCH) {
+ printf("Too many scsi changers..(%d > %d) reconfigure kernel\n", (unit + 1), NCH);
+ return (0);
}
- else
- {
+ /*
+ * Store information needed to contact our base driver
+ */
+ ch_data[unit].sc_link = sc_link;
+ sc_link->device = &ch_switch;
+ sc_link->dev_unit = unit;
+
+ /*
+ * Use the subdriver to request information regarding
+ * the drive. We cannot use interrupts yet, so the
+ * request must specify this.
+ */
+ if ((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT */ ))) {
printf("ch%d: scsi changer :- offline\n", unit);
- stat=CH_OPEN;
+ stat = CH_OPEN;
+ } else {
+ printf("ch%d: scsi changer, %d slot(s) %d drive(s) %d arm(s) %d i/e-slot(s)\n",
+ unit, ch_data[unit].slots, ch_data[unit].drives, ch_data[unit].chms, ch_data[unit].imexs);
+ stat = CH_KNOWN;
}
- ch_initialized[unit] = stat;
+ ch_data[unit].initialized = 1;
return;
}
-
-
-/*******************************************************\
-* open the device. *
-\*******************************************************/
+/*
+ * open the device.
+ */
+errval
chopen(dev)
{
- int errcode = 0;
- int unit,mode;
+ errval errcode = 0;
+ u_int32 unit, mode;
+ struct scsi_link *sc_link;
unit = UNIT(dev);
mode = MODE(dev);
- /*******************************************************\
- * Check the unit is legal *
- \*******************************************************/
- if ( unit >= NCH )
- {
- printf("ch%d: ch %d > %d\n",unit,unit,NCH);
- errcode = ENXIO;
- return(errcode);
- }
- /*******************************************************\
- * Only allow one at a time *
- \*******************************************************/
- if(ch_data[unit].flags & CH_OPEN)
- {
- printf("ch%d: already open\n",unit);
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= NCH) {
+ printf("ch%d: ch %d > %d\n", unit, unit, NCH);
errcode = ENXIO;
- goto bad;
+ return (errcode);
}
-
- if(ch_debug||(scsi_debug & (PRINTROUTINES | TRACEOPENS)))
- printf("chopen: dev=0x%x (unit %d (of %d))\n"
- , dev, unit, NCH);
- /*******************************************************\
- * Make sure the device has been initialised *
- \*******************************************************/
-
- if (!ch_initialized[unit])
- return(ENXIO);
- if (ch_initialized[unit]!=CH_KNOWN) {
- if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/)))
- {
- ch_initialized[unit]=CH_KNOWN;
- }
- else
- {
- printf("ch%d: scsi changer :- offline\n", unit);
- return(ENXIO);
- }
+ /*
+ * Only allow one at a time
+ */
+ if (ch_data[unit].flags & CH_OPEN) {
+ printf("ch%d: already open\n", unit);
+ return ENXIO;
}
- /*******************************************************\
- * Check that it is still responding and ok. *
- \*******************************************************/
-
- if(ch_debug || (scsi_debug & TRACEOPENS))
- printf("device is ");
- if (!(ch_req_sense(unit, 0)))
- {
- errcode = ENXIO;
- if(ch_debug || (scsi_debug & TRACEOPENS))
- printf("not responding\n");
- goto bad;
+ /*
+ * Make sure the device has been initialised
+ */
+ if (!ch_data[unit].initialized)
+ return (ENXIO);
+
+ sc_link = ch_data[unit].sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("chopen: dev=0x%x (unit %d (of %d))\n"
+ ,dev, unit, NCH));
+ /*
+ * Catch any unit attention errors.
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ sc_link->flags |= SDEV_OPEN;
+ /*
+ * Check that it is still responding and ok.
+ */
+ if (errcode = (scsi_test_unit_ready(sc_link, 0))) {
+ printf("ch%d: not ready\n", unit);
+ sc_link->flags &= ~SDEV_OPEN;
+ return errcode;
}
- if(ch_debug || (scsi_debug & TRACEOPENS))
- printf("ok\n");
-
- if(!(ch_test_ready(unit,0)))
- {
- printf("ch%d: not ready\n",unit);
- return(EIO);
+ /*
+ * Make sure data is loaded
+ */
+ if (errcode = (ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK))) {
+ printf("ch%d: scsi changer :- offline\n", unit);
+ sc_link->flags &= ~SDEV_OPEN;
+ return (errcode);
}
-
- ch_info_valid[unit] = TRUE;
-
- /*******************************************************\
- * Load the physical device parameters *
- \*******************************************************/
-
ch_data[unit].flags = CH_OPEN;
- return(errcode);
-bad:
- return(errcode);
+ return 0;
}
-/*******************************************************\
-* close the device.. only called if we are the LAST *
-* occurence of an open device *
-\*******************************************************/
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval
chclose(dev)
{
- unsigned char unit,mode;
+ unsigned char unit, mode;
+ struct scsi_link *sc_link;
unit = UNIT(dev);
mode = MODE(dev);
+ sc_link = ch_data[unit].sc_link;
- if(scsi_debug & TRACEOPENS)
- printf("Closing device");
+ SC_DEBUG(sc_link, SDEV_DB1, ("Closing device"));
ch_data[unit].flags = 0;
- return(0);
-}
-
-
-
-/***************************************************************\
-* chstart *
-* This routine is also called after other non-queued requests *
-* have been made of the scsi driver, to ensure that the queue *
-* continues to be drained. *
-\***************************************************************/
-/* chstart() is called at splbio */
-chstart(unit)
-{
- int drivecount;
- register struct buf *bp = 0;
- register struct buf *dp;
- struct scsi_xfer *xs;
- int blkno, nblk;
-
-
- if(scsi_debug & PRINTROUTINES) printf("chstart%d ",unit);
- /*******************************************************\
- * See if there is a buf to do and we are not already *
- * doing one *
- \*******************************************************/
- xs=&ch_scsi_xfer[unit];
- if(xs->flags & INUSE)
- {
- return; /* unit already underway */
- }
- if(ch_xfer_block_wait[unit]) /* a special awaits, let it proceed first */
- {
- wakeup(&ch_xfer_block_wait[unit]);
- return;
- }
-
- return;
-
+ sc_link->flags &= ~SDEV_OPEN;
+ return (0);
}
-
-/*******************************************************\
-* This routine is called by the scsi interrupt when *
-* the transfer is complete.
-\*******************************************************/
-int ch_done(unit,xs)
-int unit;
-struct scsi_xfer *xs;
-{
- struct buf *bp;
- int retval;
-
- if(ch_debug||(scsi_debug & PRINTROUTINES)) printf("ch_done%d ",unit);
- if (! (xs->flags & INUSE))
- panic("scsi_xfer not in use!");
- wakeup(xs);
-}
-/*******************************************************\
-* Perform special action on behalf of the user *
-* Knows about the internals of this device *
-\*******************************************************/
+/*
+ * Perform special action on behalf of the user
+ * Knows about the internals of this device
+ */
+errval
chioctl(dev, cmd, arg, mode)
-dev_t dev;
-int cmd;
-caddr_t arg;
+ dev_t dev;
+ u_int32 cmd;
+ caddr_t arg;
{
- /* struct ch_cmd_buf *args;*/
+ /* struct ch_cmd_buf *args; */
union scsi_cmd *scsi_cmd;
- register i,j;
- unsigned int opri;
- int errcode = 0;
+ register i, j;
+ u_int32 opri;
+ errval errcode = 0;
unsigned char unit;
- int number,flags,ret;
-
- /*******************************************************\
- * Find the device that the user is talking about *
- \*******************************************************/
- flags = 0; /* give error messages, act on errors etc. */
+ u_int32 number, flags;
+ errval ret;
+ struct scsi_link *sc_link;
+
+ /*
+ * Find the device that the user is talking about
+ */
+ flags = 0; /* give error messages, act on errors etc. */
unit = UNIT(dev);
-
- switch(cmd)
- {
- case CHIOOP: {
- struct chop *ch=(struct chop *) arg;
- if (ch_debug)
- printf("[chtape_chop: %x]\n", ch->ch_op);
-
- switch ((short)(ch->ch_op)) {
- case CHGETPARAM:
- ch->u.getparam.chmo= ch_data[unit].chmo;
- ch->u.getparam.chms= ch_data[unit].chms;
- ch->u.getparam.sloto= ch_data[unit].sloto;
- ch->u.getparam.slots= ch_data[unit].slots;
- ch->u.getparam.imexo= ch_data[unit].imexo;
- ch->u.getparam.imexs= ch_data[unit].imexs;
- ch->u.getparam.driveo= ch_data[unit].driveo;
- ch->u.getparam.drives= ch_data[unit].drives;
- ch->u.getparam.rot= ch_data[unit].rot;
- ch->result=0;
- return 0;
- break;
- case CHPOSITION:
- return ch_position(unit,&ch->result,ch->u.position.chm,
- ch->u.position.to,
- flags);
- case CHMOVE:
- return ch_move(unit,&ch->result, ch->u.position.chm,
- ch->u.move.from, ch->u.move.to,
- flags);
- case CHGETELEM:
- return ch_getelem(unit,&ch->result, ch->u.get_elem_stat.type,
- ch->u.get_elem_stat.from, &ch->u.get_elem_stat.elem_data,
- flags);
- default:
- return EINVAL;
+ sc_link = ch_data[unit].sc_link;
+
+ switch (cmd) {
+ case CHIOOP:{
+ struct chop *ch = (struct chop *) arg;
+ SC_DEBUG(sc_link, SDEV_DB2,
+ ("[chtape_chop: %x]\n", ch->ch_op));
+
+ switch ((short) (ch->ch_op)) {
+ case CHGETPARAM:
+ ch->u.getparam.chmo = ch_data[unit].chmo;
+ ch->u.getparam.chms = ch_data[unit].chms;
+ ch->u.getparam.sloto = ch_data[unit].sloto;
+ ch->u.getparam.slots = ch_data[unit].slots;
+ ch->u.getparam.imexo = ch_data[unit].imexo;
+ ch->u.getparam.imexs = ch_data[unit].imexs;
+ ch->u.getparam.driveo = ch_data[unit].driveo;
+ ch->u.getparam.drives = ch_data[unit].drives;
+ ch->u.getparam.rot = ch_data[unit].rot;
+ ch->result = 0;
+ return 0;
+ break;
+ case CHPOSITION:
+ return ch_position(unit, &ch->result, ch->u.position.chm,
+ ch->u.position.to,
+ flags);
+ case CHMOVE:
+ return ch_move(unit, &ch->result, ch->u.position.chm,
+ ch->u.move.from, ch->u.move.to,
+ flags);
+ case CHGETELEM:
+ return ch_getelem(unit, &ch->result, ch->u.get_elem_stat.type,
+ ch->u.get_elem_stat.from, &ch->u.get_elem_stat.elem_data,
+ flags);
+ default:
+ return EINVAL;
+ }
}
-
- }
default:
- return EINVAL;
+ return scsi_do_ioctl(sc_link, cmd, arg, mode);
}
-
- return(ret?ESUCCESS:EIO);
+ return (ret ? ESUCCESS : EIO);
}
-ch_getelem(unit,stat,type,from,data,flags)
-int unit,from,flags;
-short *stat;
-char *data;
+errval
+ch_getelem(unit, stat, type, from, data, flags)
+ u_int32 unit, from, flags;
+ short *stat;
+ char *data;
{
struct scsi_read_element_status scsi_cmd;
- char elbuf[32];
- int ret;
+ char elbuf[32];
+ errval ret;
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = READ_ELEMENT_STATUS;
scsi_cmd.byte2 = type;
- scsi_cmd.starting_element_addr[0]=(from>>8)&0xff;
- scsi_cmd.starting_element_addr[1]=from&0xff;
- scsi_cmd.number_of_elements[1]=1;
- scsi_cmd.allocation_length[2]=32;
-
- if ((ret=ch_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- elbuf,
- 32,
- 100000,
- flags) !=ESUCCESS)) {
- *stat=ch_data[unit].lsterr;
- bcopy(elbuf+16,data,16);
- return ret;
- }
- bcopy(elbuf+16,data,16); /*Just a hack sh */
+ scsi_cmd.starting_element_addr[0] = (from >> 8) & 0xff;
+ scsi_cmd.starting_element_addr[1] = from & 0xff;
+ scsi_cmd.number_of_elements[1] = 1;
+ scsi_cmd.allocation_length[2] = 32;
+
+ if ((ret = scsi_scsi_cmd(ch_data[unit].sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) elbuf,
+ 32,
+ CHRETRIES,
+ 100000,
+ NULL,
+ SCSI_DATA_IN | flags) != ESUCCESS)) {
+ *stat = ch_data[unit].lsterr;
+ bcopy(elbuf + 16, data, 16);
+ return ret;
+ }
+ bcopy(elbuf + 16, data, 16); /*Just a hack sh */
return ret;
}
-ch_move(unit,stat,chm,from,to,flags)
-int unit,chm,from,to,flags;
-short *stat;
+errval
+ch_move(unit, stat, chm, from, to, flags)
+ u_int32 unit, chm, from, to, flags;
+ short *stat;
{
struct scsi_move_medium scsi_cmd;
- int ret;
+ errval ret;
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = MOVE_MEDIUM;
- scsi_cmd.transport_element_address[0]=(chm>>8)&0xff;
- scsi_cmd.transport_element_address[1]=chm&0xff;
- scsi_cmd.source_address[0]=(from>>8)&0xff;
- scsi_cmd.source_address[1]=from&0xff;
- scsi_cmd.destination_address[0]=(to>>8)&0xff;
- scsi_cmd.destination_address[1]=to&0xff;
- scsi_cmd.invert=(chm&CH_INVERT)?1:0;
- if ((ret=ch_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- NULL,
- 0,
- 100000,
- flags) !=ESUCCESS)) {
- *stat=ch_data[unit].lsterr;
- return ret;
- }
+ scsi_cmd.transport_element_address[0] = (chm >> 8) & 0xff;
+ scsi_cmd.transport_element_address[1] = chm & 0xff;
+ scsi_cmd.source_address[0] = (from >> 8) & 0xff;
+ scsi_cmd.source_address[1] = from & 0xff;
+ scsi_cmd.destination_address[0] = (to >> 8) & 0xff;
+ scsi_cmd.destination_address[1] = to & 0xff;
+ scsi_cmd.invert = (chm & CH_INVERT) ? 1 : 0;
+ if ((ret = scsi_scsi_cmd(ch_data[unit].sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ NULL,
+ 0,
+ CHRETRIES,
+ 100000,
+ NULL,
+ flags) != ESUCCESS)) {
+ *stat = ch_data[unit].lsterr;
+ return ret;
+ }
return ret;
}
-ch_position(unit,stat,chm,to,flags)
-int unit,chm,to,flags;
-short *stat;
+errval
+ch_position(unit, stat, chm, to, flags)
+ u_int32 unit, chm, to, flags;
+ short *stat;
{
struct scsi_position_to_element scsi_cmd;
- int ret;
+ errval ret;
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = POSITION_TO_ELEMENT;
- scsi_cmd.transport_element_address[0]=(chm>>8)&0xff;
- scsi_cmd.transport_element_address[1]=chm&0xff;
- scsi_cmd.source_address[0]=(to>>8)&0xff;
- scsi_cmd.source_address[1]=to&0xff;
- scsi_cmd.invert=(chm&CH_INVERT)?1:0;
- if ((ret=ch_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- NULL,
- 0,
- 100000,
- flags) !=ESUCCESS)) {
- *stat=ch_data[unit].lsterr;
- return ret;
- }
- return ret;
-}
-
-/*******************************************************\
-* Check with the device that it is ok, (via scsi driver)*
-\*******************************************************/
-ch_req_sense(unit, flags)
-int flags;
-{
- struct scsi_sense_data sense;
- struct scsi_sense scsi_cmd;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = REQUEST_SENSE;
- scsi_cmd.length = sizeof(sense);
-
- if (ch_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(struct scsi_sense),
- &sense,
- sizeof(sense),
- 100000,
- flags | SCSI_DATA_IN) != 0)
- {
- return(FALSE);
+ scsi_cmd.transport_element_address[0] = (chm >> 8) & 0xff;
+ scsi_cmd.transport_element_address[1] = chm & 0xff;
+ scsi_cmd.source_address[0] = (to >> 8) & 0xff;
+ scsi_cmd.source_address[1] = to & 0xff;
+ scsi_cmd.invert = (chm & CH_INVERT) ? 1 : 0;
+ if ((ret = scsi_scsi_cmd(ch_data[unit].sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ NULL,
+ 0,
+ CHRETRIES,
+ 100000,
+ NULL,
+ flags) != ESUCCESS)) {
+ *stat = ch_data[unit].lsterr;
+ return ret;
}
- else
- return(TRUE);
-}
-
-/*******************************************************\
-* Get scsi driver to send a "are you ready" command *
-\*******************************************************/
-ch_test_ready(unit,flags)
-int unit,flags;
-{
- struct scsi_test_unit_ready scsi_cmd;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = TEST_UNIT_READY;
-
- if (ch_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(struct scsi_test_unit_ready),
- 0,
- 0,
- 100000,
- flags) != 0) {
- return(FALSE);
- } else
- return(TRUE);
+ return ret;
}
-
#ifdef __STDC__
#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
#else
#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 )
#endif
-/*******************************************************\
-* Get the scsi driver to send a full inquiry to the *
-* device and use the results to fill out the global *
-* parameter structure. *
-\*******************************************************/
+/*
+ * Get the scsi driver to send a full inquiry to the
+ * device and use the results to fill out the global
+ * parameter structure.
+ */
+errval
ch_mode_sense(unit, flags)
-int unit,flags;
+ u_int32 unit, flags;
{
struct scsi_mode_sense scsi_cmd;
- u_char scsi_sense[128]; /* Can't use scsi_mode_sense_data because of */
- /* missing block descriptor */
+ u_char scsi_sense[128]; /* Can't use scsi_mode_sense_data because of
+ * missing block descriptor
+ */
u_char *b;
- int i,l;
-
- /*******************************************************\
- * First check if we have it all loaded *
- \*******************************************************/
- if (ch_info_valid[unit]==CH_KNOWN) return(TRUE);
- /*******************************************************\
- * First do a mode sense *
- \*******************************************************/
- ch_info_valid[unit] &= ~CH_KNOWN;
- for(l=1;l>=0;l--) {
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = MODE_SENSE;
- scsi_cmd.byte2 = SMS_DBD;
- scsi_cmd.page = 0x3f; /* All Pages */
- scsi_cmd.length = sizeof(scsi_sense);
- /*******************************************************\
- * do the command, but we don't need the results *
- * just print them for our interest's sake *
- \*******************************************************/
- if (ch_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(struct scsi_mode_sense),
- &scsi_sense,
- sizeof(scsi_sense),
- 5000,
- flags | SCSI_DATA_IN) == 0) {
- ch_info_valid[unit] = CH_KNOWN;
- break;
- }
- }
- if (ch_info_valid[unit]!=CH_KNOWN) {
- if(!(flags & SCSI_SILENT))
+ int32 i, l;
+ errval errcode;
+ struct scsi_link *sc_link = ch_data[unit].sc_link;
+
+ /*
+ * First check if we have it all loaded
+ */
+ if (sc_link->flags & SDEV_MEDIA_LOADED)
+ return 0;
+
+ /*
+ * First do a mode sense
+ */
+ /* sc_link->flags &= ~SDEV_MEDIA_LOADED; *//*XXX */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SENSE;
+ scsi_cmd.byte2 = SMS_DBD;
+ scsi_cmd.page = 0x3f; /* All Pages */
+ scsi_cmd.length = sizeof(scsi_sense);
+
+ /*
+ * Read in the pages
+ */
+ if (errcode = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(struct scsi_mode_sense),
+ (u_char *) & scsi_sense,
+ sizeof (scsi_sense),
+ CHRETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_IN) != 0) {
+ if (!(flags & SCSI_SILENT))
printf("ch%d: could not mode sense\n", unit);
- return(FALSE);
+ return (errcode);
}
- l=scsi_sense[0]-3;
- b=&scsi_sense[4];
- /*****************************\
- * To avoid alignment problems *
- \*****************************/
-/*FIX THIS FOR MSB */
+ sc_link->flags |= SDEV_MEDIA_LOADED;
+ l = scsi_sense[0] - 3;
+ b = &scsi_sense[4];
+
+ /*
+ * To avoid alignment problems
+ */
+/* XXX - FIX THIS FOR MSB */
#define p2copy(valp) (valp[1]+ (valp[0]<<8));valp+=2
#define p4copy(valp) (valp[3]+ (valp[2]<<8) + (valp[1]<<16) + (valp[0]<<24));valp+=4
#if 0
- printf("\nmode_sense %d\n",l);
- for(i=0;i<l+4;i++) {
- printf("%x%c",scsi_sense[i],i%8==7?'\n':':');
- }
- printf("\n");
+ printf("\nmode_sense %d\n", l);
+ for (i = 0; i < l + 4; i++) {
+ printf("%x%c", scsi_sense[i], i % 8 == 7 ? '\n' : ':');
+ } printf("\n");
#endif
- for(i=0;i<l;) {
- int pc=(*b++)&0x3f;
- int pl=*b++;
- u_char *bb=b;
- switch(pc) {
- case 0x1d:
- ch_data[unit].chmo =p2copy(bb);
- ch_data[unit].chms =p2copy(bb);
- ch_data[unit].sloto =p2copy(bb);
- ch_data[unit].slots =p2copy(bb);
- ch_data[unit].imexo =p2copy(bb);
- ch_data[unit].imexs =p2copy(bb);
- ch_data[unit].driveo =p2copy(bb);
- ch_data[unit].drives =p2copy(bb);
- break;
- case 0x1e:
- ch_data[unit].rot = (*b)&1;
- break;
- case 0x1f:
- ch_data[unit].stor = *b&0xf;
- bb+=2;
- ch_data[unit].stor =p4copy(bb);
- break;
- default:
- break;
- }
- b+=pl;
- i+=pl+2;
- }
- if (ch_debug)
- {
- printf("unit %d: cht(%d-%d)slot(%d-%d)imex(%d-%d)cts(%d-%d) %s rotate\n",
- unit,
- ch_data[unit].chmo,
- ch_data[unit].chms,
- ch_data[unit].sloto,
- ch_data[unit].slots,
- ch_data[unit].imexo,
- ch_data[unit].imexs,
- ch_data[unit].driveo,
- ch_data[unit].drives,
- ch_data[unit].rot?"can":"can't");
- }
- return(TRUE);
-}
-
-/*******************************************************\
-* ask the scsi driver to perform a command for us. *
-* Call it through the switch table, and tell it which *
-* sub-unit we want, and what target and lu we wish to *
-* talk to. Also tell it where to find the command *
-* how long int is. *
-* Also tell it where to read/write the data, and how *
-* long the data is supposed to be *
-\*******************************************************/
-int ch_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags)
-
-int unit,flags;
-struct scsi_generic *scsi_cmd;
-int cmdlen;
-int timeout;
-u_char *data_addr;
-int datalen;
-{
- struct scsi_xfer *xs;
- int retval;
- int s;
-
- if(ch_debug||(scsi_debug & PRINTROUTINES)) printf("\nch_scsi_cmd%d %x",
- unit,scsi_cmd->opcode);
- if(ch_data[unit].sc_sw) /* If we have a scsi driver */
- {
-
- xs = &(ch_scsi_xfer[unit]);
- if(!(flags & SCSI_NOMASK))
- s = splbio();
- ch_xfer_block_wait[unit]++; /* there is someone waiting */
- while (xs->flags & INUSE)
- {
- sleep(&ch_xfer_block_wait[unit],PRIBIO+1);
- }
- ch_xfer_block_wait[unit]--;
- xs->flags = INUSE;
- if(!(flags & SCSI_NOMASK))
- splx(s);
-
- /*******************************************************\
- * Fill out the scsi_xfer structure *
- \*******************************************************/
- xs->flags |= flags;
- xs->adapter = ch_data[unit].ctlr;
- xs->targ = ch_data[unit].targ;
- xs->lu = ch_data[unit].lu;
- xs->retries = CH_RETRIES;
- xs->timeout = timeout;
- xs->cmd = scsi_cmd;
- xs->cmdlen = cmdlen;
- xs->data = data_addr;
- xs->datalen = datalen;
- xs->resid = datalen;
- xs->when_done = (flags & SCSI_NOMASK)
- ?(int (*)())0
- :ch_done;
- xs->done_arg = unit;
- xs->done_arg2 = (int)xs;
-retry: xs->error = XS_NOERROR;
- xs->bp = 0;
- ch_data[unit].lsterr=0;
- retval = (*(ch_data[unit].sc_sw->scsi_cmd))(xs);
- switch(retval)
- {
- case SUCCESSFULLY_QUEUED:
- while(!(xs->flags & ITSDONE))
- sleep(xs,PRIBIO+1);
-
- case HAD_ERROR:
- case COMPLETE:
- switch(xs->error)
- {
- case XS_NOERROR:
- retval = ESUCCESS;
- break;
- case XS_SENSE:
- retval = (ch_interpret_sense(unit,xs));
- break;
- case XS_DRIVER_STUFFUP:
- retval = EIO;
- break;
- case XS_TIMEOUT:
- if(xs->retries-- )
- {
- xs->flags &= ~ITSDONE;
- goto retry;
- }
- retval = EIO;
- break;
- case XS_BUSY:
- if(xs->retries-- )
- {
- xs->flags &= ~ITSDONE;
- goto retry;
- }
- retval = EIO;
- break;
- default:
- retval = EIO;
- printf("ch%d: unknown error category from scsi driver\n"
- ,unit);
- break;
- }
+ for (i = 0; i < l;) {
+ u_int32 pc = (*b++) & 0x3f;
+ u_int32 pl = *b++;
+ u_char *bb = b;
+ switch (pc) {
+ case 0x1d:
+ ch_data[unit].chmo = p2copy(bb);
+ ch_data[unit].chms = p2copy(bb);
+ ch_data[unit].sloto = p2copy(bb);
+ ch_data[unit].slots = p2copy(bb);
+ ch_data[unit].imexo = p2copy(bb);
+ ch_data[unit].imexs = p2copy(bb);
+ ch_data[unit].driveo = p2copy(bb);
+ ch_data[unit].drives = p2copy(bb);
break;
- case TRY_AGAIN_LATER:
- if(xs->retries-- )
- {
- xs->flags &= ~ITSDONE;
- goto retry;
- }
- retval = EIO;
+ case 0x1e:
+ ch_data[unit].rot = (*b) & 1;
+ break;
+ case 0x1f:
+ ch_data[unit].stor = *b & 0xf;
+ bb += 2;
+ ch_data[unit].stor = p4copy(bb);
break;
default:
- retval = EIO;
- }
- xs->flags = 0; /* it's free! */
- chstart(unit);
- }
- else
- {
- printf("ch%d: not set up\n",unit);
- return(EINVAL);
- }
- return(retval);
-}
-/***************************************************************\
-* Look at the returned sense and act on the error and detirmine *
-* The unix error number to pass back... (0 = report no error) *
-\***************************************************************/
-
-int ch_interpret_sense(unit,xs)
-int unit;
-struct scsi_xfer *xs;
-{
- struct scsi_sense_data *sense;
- int key;
- int silent = xs->flags & SCSI_SILENT;
-
- /***************************************************************\
- * If errors are ok, report a success *
- \***************************************************************/
- if(xs->flags & SCSI_ERR_OK) return(ESUCCESS);
-
- /***************************************************************\
- * Get the sense fields and work out what CLASS *
- \***************************************************************/
- sense = &(xs->sense);
- switch(sense->error_code & SSD_ERRCODE)
- {
- /***************************************************************\
- * If it's class 7, use the extended stuff and interpret the key *
- \***************************************************************/
- case 0x70:
- {
- key=sense->ext.extended.flags & SSD_KEY;
- if(sense->ext.extended.flags & SSD_ILI)
- if(!silent)
- {
- printf("length error ");
- }
- if(sense->error_code & SSD_ERRCODE_VALID)
- xs->resid = ntohl(*((long *)sense->ext.extended.info));
- if(xs->bp)
- {
- xs->bp->b_flags |= B_ERROR;
- return(ESUCCESS);
- }
- if(sense->ext.extended.flags & SSD_EOM)
- if(!silent) printf("end of medium ");
- if(sense->ext.extended.flags & SSD_FILEMARK)
- if(!silent) printf("filemark ");
- if(ch_debug)
- {
- printf("code%x valid%x\n"
- ,sense->error_code & SSD_ERRCODE
- ,sense->error_code & SSD_ERRCODE_VALID);
- printf("seg%x key%x ili%x eom%x fmark%x\n"
- ,sense->ext.extended.segment
- ,sense->ext.extended.flags & SSD_KEY
- ,sense->ext.extended.flags & SSD_ILI
- ,sense->ext.extended.flags & SSD_EOM
- ,sense->ext.extended.flags & SSD_FILEMARK);
- printf("info: %x %x %x %x followed by %d extra bytes\n"
- ,sense->ext.extended.info[0]
- ,sense->ext.extended.info[1]
- ,sense->ext.extended.info[2]
- ,sense->ext.extended.info[3]
- ,sense->ext.extended.extra_len);
- printf("extra: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n"
- ,sense->ext.extended.extra_bytes[0]
- ,sense->ext.extended.extra_bytes[1]
- ,sense->ext.extended.extra_bytes[2]
- ,sense->ext.extended.extra_bytes[3]
- ,sense->ext.extended.extra_bytes[4]
- ,sense->ext.extended.extra_bytes[5]
- ,sense->ext.extended.extra_bytes[6]
- ,sense->ext.extended.extra_bytes[7]
- ,sense->ext.extended.extra_bytes[8]
- ,sense->ext.extended.extra_bytes[9]
- ,sense->ext.extended.extra_bytes[10]
- ,sense->ext.extended.extra_bytes[11]
- ,sense->ext.extended.extra_bytes[12]
- ,sense->ext.extended.extra_bytes[13]
- ,sense->ext.extended.extra_bytes[14]
- ,sense->ext.extended.extra_bytes[15]);
-
- }
- switch(key)
- {
- case 0x0:
- return(ESUCCESS);
- case 0x1:
- if(!silent)
- {
- printf("ch%d: soft error(corrected)", unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" block no. %d (decimal)",
- (sense->ext.extended.info[0] <<24)|
- (sense->ext.extended.info[1] <<16)|
- (sense->ext.extended.info[2] <<8)|
- (sense->ext.extended.info[3] ));
- }
- printf("\n");
- }
- return(ESUCCESS);
- case 0x2:
- if(!silent) printf("ch%d: not ready\n", unit);
- ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)|
- sense->ext.extended.info[13] ;
- return(ENODEV);
- case 0x3:
- if(!silent)
- {
- printf("ch%d: medium error", unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" block no. %d (decimal)",
- (sense->ext.extended.info[0] <<24)|
- (sense->ext.extended.info[1] <<16)|
- (sense->ext.extended.info[2] <<8)|
- (sense->ext.extended.info[3] ));
- }
- printf("\n");
- }
- return(EIO);
- case 0x4:
- if(!silent) printf("ch%d: non-media hardware failure\n",
- unit);
- ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)|
- sense->ext.extended.info[13] ;
- return(EIO);
- case 0x5:
- if(!silent) printf("ch%d: illegal request\n", unit);
- ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)|
- sense->ext.extended.info[13] ;
- return(EINVAL);
- case 0x6:
- if(!silent) printf("ch%d: Unit attention\n", unit);
- ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)|
- sense->ext.extended.info[13] ;
- ch_info_valid[unit] = FALSE;
- if (ch_data[unit].flags & CH_OPEN) /* TEMP!!!! */
- return(EIO);
- else
- return(ESUCCESS);
- case 0x7:
- if(!silent)
- {
- printf("ch%d: attempted protection violation"
- , unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" block no. %d (decimal)\n",
- (sense->ext.extended.info[0] <<24)|
- (sense->ext.extended.info[1] <<16)|
- (sense->ext.extended.info[2] <<8)|
- (sense->ext.extended.info[3] ));
- }
- printf("\n");
- }
- return(EACCES);
- case 0x8:
- if(!silent)
- {
- printf("ch%d: block wrong state (worm)"
- , unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" block no. %d (decimal)",
- (sense->ext.extended.info[0] <<24)|
- (sense->ext.extended.info[1] <<16)|
- (sense->ext.extended.info[2] <<8)|
- (sense->ext.extended.info[3] ));
- }
- printf("\n");
- }
- return(EIO);
- case 0x9:
- if(!silent) printf("ch%d: vendor unique\n", unit);
- return(EIO);
- case 0xa:
- if(!silent) printf("ch%d: copy aborted\n", unit);
- return(EIO);
- case 0xb:
- if(!silent) printf("ch%d: command aborted\n", unit);
- ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)|
- sense->ext.extended.info[13] ;
- return(EIO);
- case 0xc:
- if(!silent)
- {
- printf("ch%d: search returned", unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" block no. %d (decimal)",
- (sense->ext.extended.info[0] <<24)|
- (sense->ext.extended.info[1] <<16)|
- (sense->ext.extended.info[2] <<8)|
- (sense->ext.extended.info[3] ));
- }
- printf("\n");
- }
- return(ESUCCESS);
- case 0xd:
- if(!silent) printf("ch%d: volume overflow\n", unit);
- return(ENOSPC);
- case 0xe:
- if(!silent)
- {
- printf("ch%d: verify miscompare", unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" block no. %d (decimal)",
- (sense->ext.extended.info[0] <<24)|
- (sense->ext.extended.info[1] <<16)|
- (sense->ext.extended.info[2] <<8)|
- (sense->ext.extended.info[3] ));
- }
- printf("\n");
- }
- return(EIO);
- case 0xf:
- if(!silent) printf("ch%d: unknown error key\n", unit);
- return(EIO);
- }
- break;
- }
- /***************************************************************\
- * If it's NOT class 7, just report it. *
- \***************************************************************/
- default:
- {
- if(!silent)
- {
- printf("ch%d: error code %d",
- unit,
- sense->error_code & SSD_ERRCODE);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" block no. %d (decimal)",
- (sense->ext.unextended.blockhi <<16),
- + (sense->ext.unextended.blockmed <<8),
- + (sense->ext.unextended.blocklow ));
- }
- printf("\n");
- }
+ break;
}
- return(EIO);
+ b += pl;
+ i += pl + 2;
}
+ SC_DEBUG(sc_link, SDEV_DB2,
+ (" cht(%d-%d)slot(%d-%d)imex(%d-%d)cts(%d-%d) %s rotate\n",
+ ch_data[unit].chmo, ch_data[unit].chms,
+ ch_data[unit].sloto, ch_data[unit].slots,
+ ch_data[unit].imexo, ch_data[unit].imexs,
+ ch_data[unit].driveo, ch_data[unit].drives,
+ ch_data[unit].rot ? "can" : "can't"));
+ return (0);
}
-
-
-
diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h
index 8de19b0..2e7bdcf 100644
--- a/sys/scsi/scsi_all.h
+++ b/sys/scsi/scsi_all.h
@@ -18,12 +18,11 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsi_all.h,v 1.4 1993/08/21 20:01:51 rgrimes Exp $
+ * $Id: scsi_all.h,v 2.0 93/10/06 21:10:28 julian Exp Locker: julian $
*/
-#ifndef _SCSI_SCSI_ALL_H_
-#define _SCSI_SCSI_ALL_H_ 1
-
+#ifndef _SCSI_SCSI_ALL_H
+#define _SCSI_SCSI_ALL_H 1
/*
* SCSI command format
*/
@@ -31,10 +30,10 @@
/*
* Define dome bits that are in ALL (or a lot of) scsi commands
*/
-#define SCSI_CTL_LINK 0x01
-#define SCSI_CTL_FLAG 0x02
-#define SCSI_CTL_VENDOR 0xC0
-#define SCSI_CMD_LUN 0xA0 /*these two should not be needed*/
+#define SCSI_CTL_LINK 0x01
+#define SCSI_CTL_FLAG 0x02
+#define SCSI_CTL_VENDOR 0xC0
+#define SCSI_CMD_LUN 0xA0 /* these two should not be needed */
#define SCSI_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */
@@ -103,7 +102,7 @@ struct scsi_mode_sense
struct scsi_mode_sense_big
{
u_char op_code;
- u_char byte2; /* same bits as small version */
+ u_char byte2; /* same bits as small version */
u_char page; /* same bits as small version */
u_char unused[4];
u_char length[2];
@@ -124,7 +123,7 @@ struct scsi_mode_select
struct scsi_mode_select_big
{
u_char op_code;
- u_char byte2; /* same bits as small version */
+ u_char byte2; /* same bits as small version */
u_char unused[5];
u_char length[2];
u_char control;
@@ -159,6 +158,19 @@ struct scsi_prevent
#define PR_PREVENT 0x01
#define PR_ALLOW 0x00
+struct scsi_changedef
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused1;
+ u_char how;
+ u_char unused[4];
+ u_char datalen;
+ u_char control;
+};
+#define SC_SCSI_1 0x01
+#define SC_SCSI_2 0x03
+
/*
* Opcodes
*/
@@ -173,6 +185,7 @@ struct scsi_prevent
#define RELEASE 0x17
#define PREVENT_ALLOW 0x1e
#define POSITION_TO_ELEMENT 0x2b
+#define CHANGE_DEFINITION 0x40
#define MODE_SENSE_BIG 0x54
#define MODE_SELECT_BIG 0x55
#define MOVE_MEDIUM 0xa5
@@ -234,62 +247,62 @@ struct scsi_inquiry_data
struct scsi_sense_data
{
- u_char error_code; /* same bits as new version */
+/* 1*/ u_char error_code; /* same bits as new version */
union
{
struct
{
- u_char blockhi;
- u_char blockmed;
- u_char blocklow;
+/* 2*/ u_char blockhi;
+/* 3*/ u_char blockmed;
+/* 4*/ u_char blocklow;
} unextended;
struct
{
- u_char segment;
- u_char flags; /* same bits as new version */
- u_char info[4];
- u_char extra_len;
+/* 2*/ u_char segment;
+/* 3*/ u_char flags; /* same bits as new version */
+/* 7*/ u_char info[4];
+/* 8*/ u_char extra_len;
/* allocate enough room to hold new stuff
- ( by increasing 16 to 26 below) */
- u_char extra_bytes[26];
+ ( by increasing 16 to 24 below) */
+/*32*/ u_char extra_bytes[24];
} extended;
}ext;
-};
+}; /* total of 32 bytes */
struct scsi_sense_data_new
{
- u_char error_code;
+/* 1*/ u_char error_code;
#define SSD_ERRCODE 0x7F
#define SSD_ERRCODE_VALID 0x80
union
{
- struct /* this is depreciated, the standard says "DON'T"*/
+ struct /* this is deprecated, the standard says "DON'T"*/
{
- u_char blockhi;
- u_char blockmed;
- u_char blocklow;
+/* 2*/ u_char blockhi;
+/* 3*/ u_char blockmed;
+/* 4*/ u_char blocklow;
} unextended;
struct
{
- u_char segment;
- u_char flags;
+/* 2*/ u_char segment;
+/* 3*/ u_char flags;
#define SSD_KEY 0x0F
#define SSD_ILI 0x20
#define SSD_EOM 0x40
#define SSD_FILEMARK 0x80
- u_char info[4];
- u_char extra_len;
- u_char cmd_spec_info[4];
- u_char add_sense_code;
- u_char add_sense_code_qual;
- u_char fru;
- u_char sense_key_spec_1;
+/* 7*/ u_char info[4];
+/* 8*/ u_char extra_len;
+/*12*/ u_char cmd_spec_info[4];
+/*13*/ u_char add_sense_code;
+/*14*/ u_char add_sense_code_qual;
+/*15*/ u_char fru;
+/*16*/ u_char sense_key_spec_1;
#define SSD_SCS_VALID 0x80
- u_char sense_key_spec_2;
- u_char sense_key_spec_3;
- u_char extra_bytes[16];
+/*17*/ u_char sense_key_spec_2;
+/*18*/ u_char sense_key_spec_3;
+/*32*/ u_char extra_bytes[14];
} extended;
}ext;
-};
+}; /* total of 32 bytes */
struct blk_desc
{
@@ -324,4 +337,4 @@ struct scsi_mode_header_big
#define SCSI_CHECK 0x02
#define SCSI_BUSY 0x08
#define SCSI_INTERM 0x10
-#endif /* _SCSI_SCSI_ALL_H_ */
+#endif /*_SCSI_SCSI_ALL_H*/
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c
new file mode 100644
index 0000000..a1361ec
--- /dev/null
+++ b/sys/scsi/scsi_base.c
@@ -0,0 +1,852 @@
+/*
+ * Written By Julian ELischer
+ * Copyright julian Elischer 1993.
+ * Permission is granted to use or redistribute this file in any way as long
+ * as this notice remains. Julian Elischer does not guarantee that this file
+ * is totally correct for any given task and users of this file must
+ * accept responsibility for any damage that occurs from the application of this
+ * file.
+ *
+ * Written by Julian Elischer (julian@dialix.oz.au)
+ * $Id: scsi_base.c,v 2.4 93/10/16 00:58:43 julian Exp Locker: julian $
+ */
+
+#define SPLSD splbio
+#define ESUCCESS 0
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_disk.h>
+#include <scsi/scsiconf.h>
+
+#ifdef NetBSD
+#ifdef DDB
+int Debugger();
+#else /* DDB */
+#define Debugger()
+#endif /* DDB */
+#else /* NetBSD */
+#include <ddb.h>
+#if NDDB > 0
+int Debugger();
+#else /* NDDB > 0 */
+#define Debugger()
+#endif /* NDDB > 0 */
+#endif
+
+void sc_print_addr __P((struct scsi_link *sc_link));
+
+struct scsi_xfer *next_free_xs;
+
+/*
+ * Get a scsi transfer structure for the caller. Charge the structure
+ * to the device that is referenced by the sc_link structure. If the
+ * sc_link structure has no 'credits' then the device already has the
+ * maximum number or outstanding operations under way. In this stage,
+ * wait on the structure so that when one is freed, we are awoken again
+ * If the SCSI_NOSLEEP flag is set, then do not wait, but rather, return
+ * a NULL pointer, signifying that no slots were available
+ * Note in the link structure, that we are waiting on it.
+ */
+
+struct scsi_xfer *
+get_xs(sc_link, flags)
+ struct scsi_link *sc_link; /* who to charge the xs to */
+ u_int32 flags; /* if this call can sleep */
+{
+ struct scsi_xfer *xs;
+ u_int32 s;
+
+ SC_DEBUG(sc_link, SDEV_DB3, ("get_xs\n"));
+ s = splbio();
+ while (!sc_link->opennings) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n"));
+ if (flags & SCSI_NOSLEEP) {
+ splx(s);
+ return 0;
+ }
+ sc_link->flags |= SDEV_WAITING;
+ sleep(sc_link, PRIBIO);
+ }
+ sc_link->opennings--;
+ if (xs = next_free_xs) {
+ next_free_xs = xs->next;
+ splx(s);
+ } else {
+ splx(s);
+ SC_DEBUG(sc_link, SDEV_DB3, ("making\n"));
+ xs = malloc(sizeof(*xs), M_TEMP,
+ ((flags & SCSI_NOSLEEP) ? M_NOWAIT : M_WAITOK));
+ if (xs == NULL) {
+ sc_print_addr(sc_link);
+ printf("cannot allocate scsi xs\n");
+ return (NULL);
+ }
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("returning\n"));
+ xs->sc_link = sc_link;
+ return (xs);
+}
+
+/*
+ * Given a scsi_xfer struct, and a device (referenced through sc_link)
+ * return the struct to the free pool and credit the device with it
+ * If another process is waiting for an xs, do a wakeup, let it proceed
+ */
+void
+free_xs(xs, sc_link, flags)
+ struct scsi_xfer *xs;
+ struct scsi_link *sc_link; /* who to credit for returning it */
+ u_int32 flags;
+{
+ xs->next = next_free_xs;
+ next_free_xs = xs;
+
+ SC_DEBUG(sc_link, SDEV_DB3, ("free_xs\n"));
+ /* if was 0 and someone waits, wake them up */
+ if ((!sc_link->opennings++) && (sc_link->flags & SDEV_WAITING)) {
+ wakeup(sc_link);
+ } else {
+ if (sc_link->device->start) {
+ SC_DEBUG(sc_link, SDEV_DB2, ("calling private start()\n"));
+ (*(sc_link->device->start)) (sc_link->dev_unit);
+ }
+ }
+}
+
+/*
+ * Find out from the device what its capacity is.
+ */
+u_int32
+scsi_size(sc_link, flags)
+ struct scsi_link *sc_link;
+ u_int32 flags;
+{
+ struct scsi_read_cap_data rdcap;
+ struct scsi_read_capacity scsi_cmd;
+ u_int32 size;
+
+ /*
+ * make up a scsi command and ask the scsi driver to do
+ * it for you.
+ */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_CAPACITY;
+
+ /*
+ * If the command works, interpret the result as a 4 byte
+ * number of blocks
+ */
+ if (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & rdcap,
+ sizeof(rdcap),
+ 2,
+ 20000,
+ NULL,
+ flags | SCSI_DATA_IN) != 0) {
+
+ sc_print_addr(sc_link);
+ printf("could not get size\n");
+ return (0);
+ } else {
+ size = rdcap.addr_0 + 1;
+ size += rdcap.addr_1 << 8;
+ size += rdcap.addr_2 << 16;
+ size += rdcap.addr_3 << 24;
+ }
+ return (size);
+}
+
+/*
+ * Get scsi driver to send a "are you ready?" command
+ */
+errval
+scsi_test_unit_ready(sc_link, flags)
+ struct scsi_link *sc_link;
+ u_int32 flags;
+{
+ struct scsi_test_unit_ready scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = TEST_UNIT_READY;
+
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2,
+ 100000,
+ NULL,
+ flags));
+}
+
+/*
+ * Do a scsi operation, asking a device to run as SCSI-II if it can.
+ */
+errval
+scsi_change_def(sc_link, flags)
+ struct scsi_link *sc_link;
+ u_int32 flags;
+{
+ struct scsi_changedef scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = CHANGE_DEFINITION;
+ scsi_cmd.how = SC_SCSI_2;
+
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2,
+ 100000,
+ NULL,
+ flags));
+}
+
+/*
+ * Do a scsi operation asking a device what it is
+ * Use the scsi_cmd routine in the switch table.
+ */
+errval
+scsi_inquire(sc_link, inqbuf, flags)
+ struct scsi_link *sc_link;
+ struct scsi_inquiry_data *inqbuf;
+ u_int32 flags;
+{
+ struct scsi_inquiry scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = INQUIRY;
+ scsi_cmd.length = sizeof(struct scsi_inquiry_data);
+
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) inqbuf,
+ sizeof(struct scsi_inquiry_data),
+ 2,
+ 100000,
+ NULL,
+ SCSI_DATA_IN | flags));
+}
+
+/*
+ * Prevent or allow the user to remove the media
+ */
+errval
+scsi_prevent(sc_link, type, flags)
+ struct scsi_link *sc_link;
+ u_int32 type, flags;
+{
+ struct scsi_prevent scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PREVENT_ALLOW;
+ scsi_cmd.how = type;
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2,
+ 5000,
+ NULL,
+ flags));
+}
+
+/*
+ * Get scsi driver to send a "start up" command
+ */
+errval
+scsi_start_unit(sc_link, flags)
+ struct scsi_link *sc_link;
+ u_int32 flags;
+{
+ struct scsi_start_stop scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = START_STOP;
+ scsi_cmd.how = SSS_START;
+
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2,
+ 6000,
+ NULL,
+ flags));
+}
+
+/*
+ * This routine is called by the scsi interrupt when the transfer is complete.
+ */
+void
+scsi_done(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct buf *bp = xs->bp;
+ errval retval;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n"));
+#ifdef SCSIDEBUG
+ if (sc_link->flags & SDEV_DB1)
+ {
+ show_scsi_cmd(xs);
+ }
+#endif /*SCSIDEBUG */
+ /*
+ * If it's a user level request, bypass all usual completion processing,
+ * let the user work it out.. We take reponsibility for freeing the
+ * xs when the user returns. (and restarting the device's queue).
+ */
+ if (xs->flags & SCSI_USER) {
+ biodone(xs->bp);
+#ifdef NOTNOW
+ SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n"));
+ scsi_user_done(xs); /* to take a copy of the sense etc. */
+ SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n "));
+#endif
+ free_xs(xs, sc_link, SCSI_NOSLEEP); /* restarts queue too */
+ SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n"));
+ return;
+ }
+ /*
+ * If the device has it's own done routine, call it first.
+ * If it returns a legit error value, return that, otherwise
+ * it wants us to continue with normal processing.
+ */
+
+ if (sc_link->device->done) {
+ SC_DEBUG(sc_link, SDEV_DB2, ("calling private done()\n"));
+ retval = (*sc_link->device->done) (xs);
+ if (retval == -1) {
+ free_xs(xs, sc_link, SCSI_NOSLEEP); /*XXX */
+ return; /* it did it all, finish up */
+ }
+ if (retval == -2) {
+ return; /* it did it all, finish up */
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("continuing with generic done()\n"));
+ }
+ if ((bp = xs->bp) == NULL) {
+ /*
+ * if it's a normal upper level request, then ask
+ * the upper level code to handle error checking
+ * rather than doing it here at interrupt time
+ */
+ wakeup(xs);
+ return;
+ }
+ /*
+ * Go and handle errors now.
+ * If it returns -1 then we should RETRY
+ */
+ if ((retval = sc_err1(xs)) == -1) {
+ if ((*(sc_link->adapter->scsi_cmd)) (xs)
+ == SUCCESSFULLY_QUEUED) { /* don't wake the job, ok? */
+ return;
+ }
+ xs->flags |= ITSDONE;
+ }
+ free_xs(xs, sc_link, SCSI_NOSLEEP); /* does a start if needed */
+ biodone(bp);
+}
+
+/*
+ * ask the scsi driver to perform a command for us.
+ * tell it where to read/write the data, and how
+ * long the data is supposed to be. If we have a buf
+ * to associate with the transfer, we need that too.
+ */
+errval
+scsi_scsi_cmd(sc_link, scsi_cmd, cmdlen, data_addr, datalen,
+ retries, timeout, bp, flags)
+ struct scsi_link *sc_link;
+ struct scsi_generic *scsi_cmd;
+ u_int32 cmdlen;
+ u_char *data_addr;
+ u_int32 datalen;
+ u_int32 retries;
+ u_int32 timeout;
+ struct buf *bp;
+ u_int32 flags;
+{
+ struct scsi_xfer *xs;
+ errval retval;
+ u_int32 s;
+
+ if (bp) flags |= SCSI_NOSLEEP;
+ SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n"));
+
+ xs = get_xs(sc_link, flags); /* should wait unless booting */
+ if (!xs) return (ENOMEM);
+ /*
+ * Fill out the scsi_xfer structure. We don't know whose context
+ * the cmd is in, so copy it.
+ */
+ bcopy(scsi_cmd, &(xs->cmdstore), cmdlen);
+ xs->flags = INUSE | flags;
+ xs->sc_link = sc_link;
+ xs->retries = retries;
+ xs->timeout = timeout;
+ xs->cmd = &xs->cmdstore;
+ xs->cmdlen = cmdlen;
+ xs->data = data_addr;
+ xs->datalen = datalen;
+ xs->resid = datalen;
+ xs->bp = bp;
+/*XXX*/ /*use constant not magic number */
+ if (datalen && ((caddr_t) data_addr < (caddr_t) 0xfe000000)) {
+ if (bp) {
+ printf("Data buffered space not in kernel context\n");
+#ifdef SCSIDEBUG
+ show_scsi_cmd(xs);
+#endif /* SCSIDEBUG */
+ retval = EFAULT;
+ goto bad;
+ }
+ xs->data = malloc(datalen, M_TEMP, M_WAITOK);
+ /* I think waiting is ok *//*XXX */
+ switch (flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
+ case 0:
+ printf("No direction flags, assuming both\n");
+#ifdef SCSIDEBUG
+ show_scsi_cmd(xs);
+#endif /* SCSIDEBUG */
+ case SCSI_DATA_IN | SCSI_DATA_OUT: /* weird */
+ case SCSI_DATA_OUT:
+ bcopy(data_addr, xs->data, datalen);
+ break;
+ case SCSI_DATA_IN:
+ bzero(xs->data, datalen);
+ }
+ }
+retry:
+ xs->error = XS_NOERROR;
+#ifdef PARANOID
+ if (datalen && ((caddr_t) xs->data < (caddr_t) 0xfe000000)) {
+ printf("It's still wrong!\n");
+ }
+#endif /*PARANOID*/
+#ifdef SCSIDEBUG
+ if (sc_link->flags & SDEV_DB3) show_scsi_xs(xs);
+#endif /* SCSIDEBUG */
+ /*
+ * Do the transfer. If we are polling we will return:
+ * COMPLETE, Was poll, and scsi_done has been called
+ * TRY_AGAIN_LATER, Adapter short resources, try again
+ *
+ * if under full steam (interrupts) it will return:
+ * SUCCESSFULLY_QUEUED, will do a wakeup when complete
+ * TRY_AGAIN_LATER, (as for polling)
+ * After the wakeup, we must still check if it succeeded
+ *
+ * If we have a bp however, all the error proccessing
+ * and the buffer code both expect us to return straight
+ * to them, so as soon as the command is queued, return
+ */
+
+ retval = (*(sc_link->adapter->scsi_cmd)) (xs);
+
+ switch (retval) {
+ case SUCCESSFULLY_QUEUED:
+ if (bp)
+ return retval; /* will sleep (or not) elsewhere */
+ s = splbio();
+ while (!(xs->flags & ITSDONE))
+ sleep(xs, PRIBIO + 1);
+ splx(s);
+ /* fall through to check success of completed command */
+ case COMPLETE: /* Polling command completed ok */
+/*XXX*/ case HAD_ERROR: /* Polling command completed with error */
+ SC_DEBUG(sc_link, SDEV_DB3, ("back in cmd()\n"));
+ if ((retval = sc_err1(xs)) == -1)
+ goto retry;
+ break;
+
+ case TRY_AGAIN_LATER: /* adapter resource shortage */
+ SC_DEBUG(sc_link, SDEV_DB3, ("will try again \n"));
+ /* should sleep 1 sec here */
+ if (xs->retries--) {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ default:
+ retval = EIO;
+ }
+ /*
+ * If we had to copy the data out of the user's context,
+ * then do the other half (copy it back or whatever)
+ * and free the memory buffer
+ */
+ if (datalen && (xs->data != data_addr)) {
+ switch (flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
+ case 0:
+ case SCSI_DATA_IN | SCSI_DATA_OUT: /* weird */
+ case SCSI_DATA_IN:
+ bcopy(xs->data, data_addr, datalen);
+ break;
+ }
+ free(xs->data, M_TEMP);
+ }
+ /*
+ * we have finished with the xfer stuct, free it and
+ * check if anyone else needs to be started up.
+ */
+bad:
+ free_xs(xs, sc_link, flags); /* includes the 'start' op */
+ if (bp && retval) {
+ bp->b_error = retval;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ }
+ return (retval);
+}
+
+errval
+sc_err1(xs)
+ struct scsi_xfer *xs;
+{
+ struct buf *bp = xs->bp;
+ errval retval;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("sc_err1,err = 0x%x \n", xs->error));
+ /*
+ * If it has a buf, we might be working with
+ * a request from the buffer cache or some other
+ * piece of code that requires us to process
+ * errors at inetrrupt time. We have probably
+ * been called by scsi_done()
+ */
+ switch (xs->error) {
+ case XS_NOERROR: /* nearly always hit this one */
+ retval = ESUCCESS;
+ if (bp) {
+ bp->b_error = 0;
+ bp->b_resid = 0;
+ }
+ break;
+
+ case XS_SENSE:
+ if (bp) {
+ bp->b_error = 0;
+ bp->b_resid = 0;
+ if (retval = (scsi_interpret_sense(xs))) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = retval;
+ bp->b_resid = bp->b_bcount;
+ }
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("scsi_interpret_sense (bp) returned %d\n", retval));
+ } else {
+ retval = (scsi_interpret_sense(xs));
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("scsi_interpret_sense (no bp) returned %d\n", retval));
+ }
+ break;
+
+ case XS_BUSY:
+ /*should somehow arange for a 1 sec delay here (how?) */
+ case XS_TIMEOUT:
+ /*
+ * If we can, resubmit it to the adapter.
+ */
+ if (xs->retries--) {
+ xs->error = XS_NOERROR;
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ /* fall through */
+ case XS_DRIVER_STUFFUP:
+ if (bp) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ }
+ retval = EIO;
+ break;
+ default:
+ retval = EIO;
+ sc_print_addr(xs->sc_link);
+ printf("unknown error category from scsi driver\n");
+ }
+ return retval;
+retry:
+ return (-1);
+}
+
+/*
+ * Look at the returned sense and act on the error, determining
+ * the unix error number to pass back. (0 = report no error)
+ *
+ * THIS IS THE DEFAULT ERROR HANDLER
+ */
+errval
+scsi_interpret_sense(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *sense;
+ struct scsi_link *sc_link = xs->sc_link;
+ u_int32 key;
+ u_int32 silent;
+ u_int32 info;
+ errval errcode;
+
+ static char *error_mes[] =
+ {"soft error (corrected)",
+ "not ready", "medium error",
+ "non-media hardware failure", "illegal request",
+ "unit attention", "readonly device",
+ "no data found", "vendor unique",
+ "copy aborted", "command aborted",
+ "search returned equal", "volume overflow",
+ "verify miscompare", "unknown error key"
+ };
+
+ /*
+ * If the flags say errs are ok, then always return ok.
+ */
+ if (xs->flags & SCSI_ERR_OK)
+ return (ESUCCESS);
+
+ sense = &(xs->sense);
+#ifdef SCSIDEBUG
+ if (sc_link->flags & SDEV_DB1) {
+ u_int32 count = 0;
+ printf("code%x valid%x ",
+ sense->error_code & SSD_ERRCODE,
+ sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
+ printf("seg%x key%x ili%x eom%x fmark%x\n",
+ sense->ext.extended.segment,
+ sense->ext.extended.flags & SSD_KEY,
+ sense->ext.extended.flags & SSD_ILI ? 1 : 0,
+ sense->ext.extended.flags & SSD_EOM ? 1 : 0,
+ sense->ext.extended.flags & SSD_FILEMARK ? 1 : 0);
+ printf("info: %x %x %x %x followed by %d extra bytes\n",
+ sense->ext.extended.info[0],
+ sense->ext.extended.info[1],
+ sense->ext.extended.info[2],
+ sense->ext.extended.info[3],
+ sense->ext.extended.extra_len);
+ printf("extra: ");
+ while (count < sense->ext.extended.extra_len) {
+ printf("%x ", sense->ext.extended.extra_bytes[count++]);
+ }
+ printf("\n");
+ }
+#endif /*SCSIDEBUG */
+ /*
+ * If the device has it's own error handler, call it first.
+ * If it returns a legit error value, return that, otherwise
+ * it wants us to continue with normal error processing.
+ */
+ if (sc_link->device->err_handler) {
+ SC_DEBUG(sc_link, SDEV_DB2, ("calling private err_handler()\n"));
+ errcode = (*sc_link->device->err_handler) (xs);
+ if (errcode != -1)
+ return errcode; /* errcode >= 0 better ? */
+ }
+ /* otherwise use the default */
+ silent = (xs->flags & SCSI_SILENT);
+ switch (sense->error_code & SSD_ERRCODE) {
+ /*
+ * If it's code 70, use the extended stuff and interpret the key
+ */
+ case 0x71: /* delayed error */
+ sc_print_addr(sc_link);
+ key = sense->ext.extended.flags & SSD_KEY;
+ printf(" DELAYED ERROR, key = 0x%x\n", key);
+ case 0x70:
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ info = ntohl(*((long *) sense->ext.extended.info));
+ } else {
+ info = 0;
+ }
+ key = sense->ext.extended.flags & SSD_KEY;
+
+ if (key && !silent) {
+ sc_print_addr(sc_link);
+ printf("%s", error_mes[key - 1]);
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ switch (key) {
+ case 0x2: /* NOT READY */
+ case 0x5: /* ILLEGAL REQUEST */
+ case 0x6: /* UNIT ATTENTION */
+ case 0x7: /* DATA PROTECT */
+ break;
+ case 0x8: /* BLANK CHECK */
+ printf(", requested size: %d (decimal)",
+ info);
+ break;
+ default:
+ printf(", info = %d (decimal)", info);
+ }
+ }
+ printf("\n");
+ }
+ switch (key) {
+ case 0x0: /* NO SENSE */
+ case 0x1: /* RECOVERED ERROR */
+ if (xs->resid == xs->datalen)
+ xs->resid = 0; /* not short read */
+ case 0xc: /* EQUAL */
+ return (ESUCCESS);
+ case 0x2: /* NOT READY */
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+ return (EBUSY);
+ case 0x5: /* ILLEGAL REQUEST */
+ return (EINVAL);
+ case 0x6: /* UNIT ATTENTION */
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+ if (sc_link->flags & SDEV_OPEN) {
+ return (EIO);
+ } else {
+ return 0;
+ }
+ case 0x7: /* DATA PROTECT */
+ return (EACCES);
+ case 0xd: /* VOLUME OVERFLOW */
+ return (ENOSPC);
+ case 0x8: /* BLANK CHECK */
+ return (ESUCCESS);
+ default:
+ return (EIO);
+ }
+ /*
+ * Not code 70, just report it
+ */
+ default:
+ if (!silent) {
+ sc_print_addr(sc_link);
+ printf("error code %d",
+ sense->error_code & SSD_ERRCODE);
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ printf(" at block no. %d (decimal)",
+ (sense->ext.unextended.blockhi << 16) +
+ (sense->ext.unextended.blockmed << 8) +
+ (sense->ext.unextended.blocklow));
+ }
+ printf("\n");
+ }
+ return (EIO);
+ }
+}
+
+/*
+ * Utility routines often used in SCSI stuff
+ */
+
+/*
+ * convert a physical address to 3 bytes,
+ * MSB at the lowest address,
+ * LSB at the highest.
+ */
+void
+lto3b(val, bytes)
+ int val;
+ u_char *bytes;
+{
+ *bytes++ = (val & 0xff0000) >> 16;
+ *bytes++ = (val & 0xff00) >> 8;
+ *bytes = val & 0xff;
+}
+
+/*
+ * The reverse of lto3b
+ */
+int
+_3btol(bytes)
+ u_char *bytes;
+{
+ u_int32 rc;
+ rc = (*bytes++ << 16);
+ rc += (*bytes++ << 8);
+ rc += *bytes;
+ return ((int) rc);
+}
+
+/*
+ * Print out the scsi_link structure's address info.
+ */
+
+void
+sc_print_addr(sc_link)
+ struct scsi_link *sc_link;
+{
+
+ printf("%s%d(%s%d:%d:%d): ", sc_link->device->name, sc_link->dev_unit,
+ sc_link->adapter->name, sc_link->adapter_unit,
+ sc_link->target, sc_link->lun);
+}
+#ifdef SCSIDEBUG
+/*
+ * Given a scsi_xfer, dump the request, in all it's glory
+ */
+void
+show_scsi_xs(xs)
+ struct scsi_xfer *xs;
+{
+ printf("xs(0x%x): ", xs);
+ printf("flg(0x%x)", xs->flags);
+ printf("sc_link(0x%x)", xs->sc_link);
+ printf("retr(0x%x)", xs->retries);
+ printf("timo(0x%x)", xs->timeout);
+ printf("cmd(0x%x)", xs->cmd);
+ printf("len(0x%x)", xs->cmdlen);
+ printf("data(0x%x)", xs->data);
+ printf("len(0x%x)", xs->datalen);
+ printf("res(0x%x)", xs->resid);
+ printf("err(0x%x)", xs->error);
+ printf("bp(0x%x)", xs->bp);
+ show_scsi_cmd(xs);
+}
+
+void
+show_scsi_cmd(struct scsi_xfer *xs)
+{
+ u_char *b = (u_char *) xs->cmd;
+ int i = 0;
+
+ sc_print_addr(xs->sc_link);
+ printf("command: ");
+
+ if (!(xs->flags & SCSI_RESET)) {
+ while (i < xs->cmdlen) {
+ if (i)
+ printf(",");
+ printf("%x", b[i++]);
+ }
+ printf("-[%d bytes]\n", xs->datalen);
+ if (xs->datalen)
+ show_mem(xs->data, min(64, xs->datalen));
+ } else {
+ printf("-RESET-\n");
+ }
+}
+
+void
+show_mem(address, num)
+ unsigned char *address;
+ u_int32 num;
+{
+ u_int32 x, y;
+ printf("------------------------------");
+ for (y = 0; y < num; y += 1) {
+ if (!(y % 16))
+ printf("\n%03d: ", y);
+ printf("%02x ", *address++);
+ }
+ printf("\n------------------------------\n");
+}
+#endif /*SCSIDEBUG */
diff --git a/sys/scsi/scsi_cd.h b/sys/scsi/scsi_cd.h
index e9e80de..0a4759b 100644
--- a/sys/scsi/scsi_cd.h
+++ b/sys/scsi/scsi_cd.h
@@ -14,11 +14,10 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsi_cd.h,v 1.4 1993/08/21 20:01:52 rgrimes Exp $
+ * $Id: scsi_cd.h,v 1.6 93/08/26 21:09:19 julian Exp Locker: julian $
*/
-
-#ifndef _SCSI_SCSI_CD_H_
-#define _SCSI_SCSI_CD_H_ 1
+#ifndef _SCSI_SCSI_CD_H
+#define _SCSI_SCSI_CD_H 1
/*
* Define two bits always in the same place in byte 2 (flag byte)
@@ -142,6 +141,7 @@ struct scsi_read_toc
u_char data_len[2];
u_char control;
};
+;
struct scsi_read_cd_capacity
{
@@ -225,5 +225,5 @@ struct cd_mode_data
struct blk_desc blk_desc;
union cd_pages page;
};
+#endif /*_SCSI_SCSI_CD_H*/
-#endif /* _SCSI_SCSI_CD_H_ */
diff --git a/sys/scsi/scsi_changer.h b/sys/scsi/scsi_changer.h
index dda22ee..85819c8 100644
--- a/sys/scsi/scsi_changer.h
+++ b/sys/scsi/scsi_changer.h
@@ -19,11 +19,10 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsi_changer.h,v 1.4 1993/08/21 20:01:53 rgrimes Exp $
+ * $Id: scsi_changer.h,v 1.5 93/08/26 21:09:22 julian Exp Locker: julian $
*/
-
-#ifndef _SCSI_SCSI_CHANGER_H_
-#define _SCSI_SCSI_CHANGER_H_ 1
+#ifndef _SCSI_SCSI_CHANGER_H
+#define _SCSI_SCSI_CHANGER_H 1
/*
* SCSI command format
@@ -95,5 +94,5 @@ struct element_status_page
u_char rsvd;
u_char byte_count_of_descriptor_data[3];
};
+#endif /*_SCSI_SCSI_CHANGER_H*/
-#endif /* _SCSI_SCSI_CHANGER_H_ */
diff --git a/sys/scsi/scsi_debug.h b/sys/scsi/scsi_debug.h
new file mode 100644
index 0000000..480ff14
--- /dev/null
+++ b/sys/scsi/scsi_debug.h
@@ -0,0 +1,53 @@
+/*#define SCSIDEBUG 1*/
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ *
+ * $Id: scsi_debug.h,v 1.3 93/10/10 09:26:05 julian Exp Locker: julian $
+ */
+#ifndef _SCSI_SCSI_DEBUG_H
+#define _SCSI_SCSI_DEBUG_H 1
+
+/*
+ * These are the new debug bits. (Sat Oct 2 12:46:46 WST 1993)
+ * the following DEBUG bits are defined to exist in the flags word of
+ * the scsi_link structure.
+ */
+#define SDEV_DB1 0x10 /* scsi commands, errors, data */
+#define SDEV_DB2 0x20 /* routine flow tracking */
+#define SDEV_DB3 0x40 /* internal to routine flows */
+#define SDEV_DB4 0x80 /* level 4 debugging for this dev */
+
+/* target and LUN we want to debug */
+#define DEBUGTARG 9 /*9 = dissable*/
+#define DEBUGLUN 0
+#define DEBUGLEVEL (SDEV_DB1|SDEV_DB2)
+
+/*
+ * This is the usual debug macro for use with the above bits
+ */
+#ifdef SCSIDEBUG
+#define SC_DEBUG(sc_link,Level,Printstuff) \
+ if((sc_link)->flags & (Level)) \
+ { \
+ printf("%s%d(%s%d:%d:%d): ", \
+ sc_link->device->name, \
+ sc_link->dev_unit, \
+ sc_link->adapter->name, \
+ sc_link->adapter_unit, \
+ sc_link->target, \
+ sc_link->lun); \
+ printf Printstuff; \
+ }
+#define SC_DEBUGN(sc_link,Level,Printstuff) \
+ if((sc_link)->flags & (Level)) \
+ { \
+ printf Printstuff; \
+ }
+#else
+#define SC_DEBUG(A,B,C) /* not included */
+#define SC_DEBUGN(A,B,C) /* not included */
+#endif
+
+#endif /*_SCSI_SCSI_DEBUG_H*/
+/* END OF FILE */
+
diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h
index e9cb724..60d0bcc 100644
--- a/sys/scsi/scsi_disk.h
+++ b/sys/scsi/scsi_disk.h
@@ -3,7 +3,7 @@
*/
/*
- * Some lines of this file comes from a file of the name "scsi.h"
+ * Some lines of this file come from a file of the name "scsi.h"
* distributed by OSF as part of mach2.5,
* so the following disclaimer has been kept.
*
@@ -46,16 +46,15 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsi_disk.h,v 1.4 1993/08/21 20:01:54 rgrimes Exp $
+ * $Id: scsi_disk.h,v 1.4 93/08/26 21:09:23 julian Exp Locker: julian $
*/
-#ifndef _SCSI_SCSI_DISK_H_
-#define _SCSI_SCSI_DISK_H_ 1
-
/*
* SCSI command format
*/
+#ifndef _SCSI_SCSI_DISK_H
+#define _SCSI_SCSI_DISK_H 1
struct scsi_reassign_blocks
{
@@ -214,4 +213,4 @@ union disk_pages /* this is the structure copied from osf */
u_char reserved3;
} rigid_geometry;
} ;
-#endif /* _SCSI_SCSI_DISK_H_ */
+#endif /* _SCSI_SCSI_DISK_H*/
diff --git a/sys/scsi/scsi_ioctl.c b/sys/scsi/scsi_ioctl.c
new file mode 100644
index 0000000..c1b576d
--- /dev/null
+++ b/sys/scsi/scsi_ioctl.c
@@ -0,0 +1,329 @@
+/*
+ * Contributed by HD Associates (hd@world.std.com).
+ * Copyright (c) 1992, 1993 HD Associates
+ *
+ * Berkeley style copyright.
+ *
+ *
+ */
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#define b_screq b_driver1 /* a patch in buf.h */
+#define b_sc_link b_driver2 /* a patch in buf.h */
+#include <sys/proc.h>
+
+#include "scbus.h"
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <sys/scsiio.h>
+
+
+/*
+ * We let the user interpret his own sense in the generic scsi world.
+ * This routine is called at interrupt time if the SCSI_USER bit was set
+ * in the flags passed to scsi_scsi_cmd(). No other completion processing
+ * takes place, even if we are running over another device driver.
+ * The lower level routines that call us here, will free the xs and restart
+ * the device's queue if such exists.
+ */
+#ifndef min
+#define min(A,B) ((A<B) ? A : B )
+#endif
+
+void scsi_user_done(xs)
+struct scsi_xfer *xs;
+{
+
+ struct buf *bp;
+ scsireq_t *screq;
+
+ bp = xs->bp;
+ if(!bp) { /* ALL user requests must have a buf */
+ sc_print_addr(xs->sc_link);
+ printf("User command with no buf\n");
+ return ;
+ }
+ screq = bp->b_screq;
+ if (!screq) { /* Is it one of ours? (the SCSI_USER bit says it is) */
+ sc_print_addr(xs->sc_link);
+ printf("User command with no request\n");
+ return ;
+ }
+
+ SC_DEBUG(xs->sc_link,SDEV_DB2,("user-done\n"));
+ screq->retsts = 0;
+ screq->status = xs->status;
+ switch(xs->error) {
+ case XS_NOERROR:
+ SC_DEBUG(xs->sc_link,SDEV_DB3,("no error\n"));
+ screq->datalen_used = xs->datalen - xs->resid; /* probably rubbish */
+ screq->retsts = SCCMD_OK;
+ break;
+
+ case XS_SENSE:
+ SC_DEBUG(xs->sc_link,SDEV_DB3,("have sense\n"));
+ screq->senselen_used = min(sizeof(xs->sense),SENSEBUFLEN);
+ bcopy(&xs->sense,screq->sense,screq->senselen);
+ screq->retsts = SCCMD_SENSE;
+ break;
+
+ case XS_DRIVER_STUFFUP:
+ sc_print_addr(xs->sc_link);
+ printf("host adapter code inconsistency\n");
+ screq->retsts = SCCMD_UNKNOWN;
+ break;
+
+ case XS_TIMEOUT:
+ SC_DEBUG(xs->sc_link,SDEV_DB3,("timeout\n"));
+ screq->retsts = SCCMD_TIMEOUT;
+ break;
+
+ case XS_BUSY:
+ SC_DEBUG(xs->sc_link,SDEV_DB3,("busy\n"));
+ screq->retsts = SCCMD_BUSY;
+ break;
+
+ default:
+ sc_print_addr(xs->sc_link);
+ printf("unknown error category from host adapter code\n");
+ screq->retsts = SCCMD_UNKNOWN;
+ break;
+ }
+ biodone(bp); /* we're waiting on it in scsi_strategy() */
+ return; /* it'll free the xs and restart any queue */
+}
+
+
+/* Pseudo strategy function
+ * Called by scsi_do_ioctl() via physio/physstrat if there is to
+ * be data transfered, and directly if there is no data transfer.
+ *
+ * Should I reorganize this so it returns to physio instead
+ * of sleeping in scsiio_scsi_cmd? Is there any advantage, other
+ * than avoiding the probable duplicate wakeup in iodone? [PD]
+ *
+ * No, seems ok to me... [JRE]
+ * (I don't see any duplicate wakeups)
+ *
+ * Can't be used with block devices or raw_read/raw_write directly
+ * from the cdevsw/bdevsw tables because they couldn't have added
+ * the screq structure. [JRE]
+ */
+void scsistrategy(struct buf *bp)
+{
+ errval err;
+ struct scsi_link *sc_link = bp->b_sc_link;
+ scsireq_t *screq;
+ u_int32 flags = 0;
+ int s;
+
+
+ if(!sc_link) {
+ printf("user_strat: No link pointer\n");
+ scsierr(bp,EINVAL);
+ return;
+ }
+ SC_DEBUG(sc_link,SDEV_DB2,("user_strategy\n"));
+ screq = bp->b_screq;
+ if(!screq) {
+ sc_print_addr(sc_link);
+ printf("No request block\n");
+ scsierr(bp,EINVAL);
+ return;
+ }
+
+ /* We're in trouble if physio tried to break up the
+ * transfer:
+ */
+ if (bp->b_bcount != screq->datalen) {
+ sc_print_addr(sc_link);
+ printf("physio split the request.. cannot proceed\n");
+ scsierr(bp, EIO);
+ return;
+ }
+
+ if (screq->timeout == 0) {
+ scsierr(bp, EINVAL);
+ return;
+ }
+
+ if (screq->cmdlen > sizeof(struct scsi_generic)) {
+ sc_print_addr(sc_link);
+ printf("cmdlen too big ");
+ scsierr(bp, EFAULT);
+ return;
+ }
+
+
+ if (screq->flags & SCCMD_READ)
+ flags |= SCSI_DATA_IN;
+
+ if (screq->flags & SCCMD_WRITE)
+ flags |= SCSI_DATA_OUT;
+
+ if (screq->flags & SCCMD_TARGET)
+ flags |= SCSI_TARGET;
+
+ if (screq->flags & SCCMD_ESCAPE)
+ flags |= SCSI_ESCAPE;
+ err = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *)screq->cmd,
+ screq->cmdlen,
+ (u_char *)bp->b_un.b_addr,
+ screq->datalen,
+ 0, /* user must do the retries *//* ignored */
+ screq->timeout,
+ bp,
+ flags | SCSI_USER);
+
+
+
+ /*because there is a bp, scsi_scsi_cmd will return immediatly*/
+ if (err)
+ {
+ scsierr(bp, err);
+ return;
+ }
+ SC_DEBUG(sc_link,SDEV_DB3,("about to sleep\n"));
+ s = splbio();
+ while(!(bp->b_flags & B_DONE))
+ {
+ sleep(bp,PRIBIO);
+ }
+ splx(s);
+ SC_DEBUG(sc_link,SDEV_DB3,("back from sleep\n"));
+ return;
+}
+
+void scsiminphys(struct buf *bp)
+{
+ /*XXX*//* call the adapter's minphys */
+}
+
+
+/*
+ * Something (e.g. another driver) has called us
+ * with an sc_link for a target/lun/adapter, and a scsi
+ * specific ioctl to perform, better try.
+ * If user-level type command, we must still be running
+ * in the context of the calling process
+ */
+errval scsi_do_ioctl(struct scsi_link *sc_link, int cmd, caddr_t addr, int f)
+{
+ errval ret = 0;
+ int phys;
+
+ SC_DEBUG(sc_link,SDEV_DB2,("scsi_do_ioctl(0x%x)\n",cmd));
+ switch(cmd)
+ {
+#ifndef NetBSD
+ case SCIOCCOMMAND:
+ {
+ /*
+ * You won't believe this, but the arg copied in
+ * from the user space, is on the kernel stack
+ * for this process, so we can't write
+ * to it at interrupt time..
+ * we need to copy it in and out!
+ * Make a static copy using malloc!
+ */
+ scsireq_t *screq2 = (scsireq_t *)addr;
+ scsireq_t *screq = (scsireq_t *)addr;
+ int rwflag = (screq->flags & SCCMD_READ) ? B_READ : B_WRITE;
+ struct buf *bp;
+ caddr_t d_addr;
+ int len;
+
+ if((unsigned int)screq < (unsigned int)0xfe000000)
+ {
+ screq = malloc(sizeof(scsireq_t),M_TEMP,M_WAITOK);
+ bcopy(screq2,screq,sizeof(scsireq_t));
+ }
+ bp = malloc(sizeof (struct buf),M_TEMP,M_WAITOK);
+ bzero(bp,sizeof(struct buf));
+ d_addr = screq->databuf;
+ bp->b_bcount = len = screq->datalen;
+ bp->b_screq = screq;
+ bp->b_sc_link = sc_link;
+ if (len) {
+ /* have data, translate it. (physio)*/
+#ifdef __NetBSD__
+#error "dev, mincntfn & uio need defining"
+ ret = physio(scsistrategy, bp, dev, rwflag,
+ mincntfn, uio);
+#else
+ ret = physio(scsistrategy,0,bp,0,rwflag,
+ d_addr,&len,curproc);
+#endif
+ } else {
+ /* if no data, no need to translate it.. */
+ bp->b_un.b_addr = 0;
+ bp->b_dev = -1; /* irrelevant info */
+ bp->b_flags = 0;
+
+ scsistrategy(bp);
+ ret = bp->b_error;
+ }
+ free(bp,M_TEMP);
+ if((unsigned int)screq2 < (unsigned int)0xfe000000)
+ {
+ bcopy(screq,screq2,sizeof(scsireq_t));
+ free(screq,M_TEMP);
+ }
+ break;
+ }
+#endif /* !NetBSD */
+ case SCIOCDEBUG:
+ {
+ int level = *((int *)addr);
+ SC_DEBUG(sc_link,SDEV_DB3,("debug set to %d\n",level));
+ sc_link->flags &= ~SDEV_DBX; /*clear debug bits */
+ if(level & 1) sc_link->flags |= SDEV_DB1;
+ if(level & 2) sc_link->flags |= SDEV_DB2;
+ if(level & 4) sc_link->flags |= SDEV_DB3;
+ if(level & 8) sc_link->flags |= SDEV_DB4;
+ ret = 0;
+ break;
+ }
+ case SCIOCREPROBE:
+ {
+ extern int scsibus;
+ struct scsi_addr *sca = (struct scsi_addr *) addr;
+
+ ret = scsi_probe_busses(sca->scbus,sca->target,sca->lun);
+ break;
+ }
+ case SCIOCRECONFIG:
+ case SCIOCDECONFIG:
+ ret = EINVAL;
+ break;
+ case SCIOCIDENTIFY:
+ {
+ struct scsi_addr *sca = (struct scsi_addr *) addr;
+ sca->scbus = sc_link->scsibus;
+ sca->target = sc_link->target;
+ sca->lun = sc_link->lun;
+ break;
+ }
+
+ default:
+ ret = ENOTTY;
+ break;
+ }
+
+ return ret;
+}
+
+scsierr(bp,err)
+struct buf *bp;
+int err;
+{
+ bp->b_flags |= B_ERROR;
+ bp->b_error = err;
+ biodone(bp);
+ return;
+}
+
diff --git a/sys/scsi/scsi_tape.h b/sys/scsi/scsi_tape.h
index 103e116..ac417c2 100644
--- a/sys/scsi/scsi_tape.h
+++ b/sys/scsi/scsi_tape.h
@@ -21,13 +21,12 @@
/*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsi_tape.h,v 1.6 1993/09/05 15:42:20 rgrimes Exp $
+ * $Id: scsi_tape.h,v 1.8 93/08/31 21:40:16 julian Exp Locker: julian $
*/
+#ifndef SCSI_SCSI_TAPE_H
+#define SCSI_SCSI_TAPE_H 1
-#ifndef _SCSI_SCSI_TAPE_H_
-#define _SCSI_SCSI_TAPE_H_ 1
-
/*
* SCSI command formats
@@ -200,7 +199,6 @@ struct blk_desc_cipher
#define QIC_525 0x11
#define QIC_1320 0x12
#define DDS 0x13
-#define DAT-1 0x13
-
+#define DAT_1 0x13
-#endif /* _SCSI_SCSI_TAPE_H_ */
+#endif /*SCSI_SCSI_TAPE_H*/
diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c
index 70765b0..708cc7c 100644
--- a/sys/scsi/scsiconf.c
+++ b/sys/scsi/scsiconf.c
@@ -14,768 +14,686 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsiconf.c,v 1.5 1993/08/28 03:08:53 rgrimes Exp $
+ * $Id: scsiconf.c,v 2.6 93/10/24 12:43:51 julian Exp Locker: julian $
*/
#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/malloc.h>
#include "st.h"
#include "sd.h"
#include "ch.h"
#include "cd.h"
-#include "sg.h"
+#include "uk.h"
+#include "su.h"
+#ifndef NSCBUS
+#define NSCBUS 8
+#endif /* NSCBUS */
-#ifdef MACH
-#include <i386/machparam.h>
-#endif MACH
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
-#if !defined(OSF) && !defined(__386BSD__)
+#ifdef TFS
#include "bll.h"
#include "cals.h"
#include "kil.h"
-#else
+#include "scan.h"
+#else /* TFS */
#define NBLL 0
#define NCALS 0
#define NKIL 0
-#endif /* !defined(OSF) && !defined(__386BSD__) */
+#define NSCAN 0
+#endif /* TFS */
#if NSD > 0
-extern sdattach();
-#endif NSD
+extern sdattach();
+#endif /* NSD */
#if NST > 0
-extern stattach();
-#endif NST
+extern stattach();
+#endif /* NST */
#if NCH > 0
-extern chattach();
-#endif NCH
+extern chattach();
+#endif /* NCH */
#if NCD > 0
-extern cdattach();
-#endif NCD
+extern cdattach();
+#endif /* NCD */
#if NBLL > 0
-extern bllattach();
-#endif NBLL
+extern bllattach();
+#endif /* NBLL */
#if NCALS > 0
-extern calsattach();
-#endif NCALS
+extern calsattach();
+#endif /* NCALS */
#if NKIL > 0
-extern kil_attach();
-#endif NKIL
-
-/***************************************************************\
-* The structure of pre-configured devices that might be turned *
-* off and therefore may not show up *
-\***************************************************************/
-struct predefined
-{
- u_char scsibus;
- u_char dev;
- u_char lu;
- int (*attach_rtn)();
- char *devname;
- char flags;
-}
-pd[] =
+extern kil_attach();
+#endif /* NKIL */
+#if NUK > 0
+extern ukattach();
+#endif /* NUK */
+
+/*
+ * One of these is allocated and filled in for each scsi bus.
+ * it holds pointers to allow the scsi bus to get to the driver
+ * That is running each LUN on the bus
+ * it also has a template entry which is the prototype struct
+ * supplied by the adapter driver, this is used to initialise
+ * the others, before they have the rest of the fields filled in
+ */
+struct scsibus_data *scbus_data[NSCBUS];
+
+/*
+ * The structure of pre-configured devices that might be turned
+ * off and therefore may not show up
+ */
+struct predefined {
+ u_char scsibus;
+ u_char dev;
+ u_char lu;
+ errval(*attach_rtn) ();
+ char *devname;
+ char flags;
+} pd[] =
+
{
#ifdef EXAMPLE_PREDEFINE
#if NSD > 0
- {0,0,0,sdattach,"sd",0},/* define a disk at scsibus=0 dev=0 lu=0 */
-#endif NSD
-#endif EXAMPLE_PREDEFINE
- {0,9,9} /*illegal dummy end entry */
+ {
+ 0, 0, 0, sdattach, "sd", 0
+ }, /* define a disk at scsibus=0 dev=0 lu=0 */
+#endif /* NSD */
+#endif /* EXAMPLE_PREDEFINE */
+ {
+ 0, 9, 9
+ } /*illegal dummy end entry */
};
+/*
+ * The structure of known drivers for autoconfiguration
+ */
+struct scsidevs {
+ u_int32 type;
+ boolean removable;
+ char *manufacturer;
+ char *model;
+ char *version;
+ errval(*attach_rtn) ();
+ char *devname;
+ char flags; /* 1 show my comparisons during boot(debug) */
+};
-/***************************************************************\
-* The structure of known drivers for autoconfiguration *
-\***************************************************************/
-static struct scsidevs
-{
- int type;
- int removable;
- char *manufacturer;
- char *model;
- char *version;
- int (*attach_rtn)();
- char *devname;
- char flags; /* 1 show my comparisons during boot(debug) */
-}
#define SC_SHOWME 0x01
#define SC_ONE_LU 0x00
#define SC_MORE_LUS 0x02
-knowndevs[] = {
+#if NUK > 0
+
+static struct scsidevs unknowndev = {
+ -1, 0, "standard", "any"
+ ,"any", ukattach, "uk", SC_MORE_LUS
+};
+#endif /*NUK*/
+static struct scsidevs knowndevs[] =
+{
#if NSD > 0
- { T_DIRECT,T_FIXED,"standard","any"
- ,"any",sdattach,"sd",SC_ONE_LU },
- { T_DIRECT,T_FIXED,"MAXTOR ","XT-4170S "
- ,"B5A ",sdattach,"mx1",SC_ONE_LU },
-#endif NSD
+ {
+ T_DIRECT, T_FIXED, "standard", "any"
+ ,"any", sdattach, "sd", SC_ONE_LU
+ },
+ {
+ T_DIRECT, T_FIXED, "MAXTOR ", "XT-4170S "
+ ,"B5A ", sdattach, "mx1", SC_ONE_LU
+ },
+#endif /* NSD */
#if NST > 0
- { T_SEQUENTIAL,T_REMOV,"standard","any"
- ,"any",stattach,"st",SC_ONE_LU },
-#endif NST
+ {
+ T_SEQUENTIAL, T_REMOV, "standard", "any"
+ ,"any", stattach, "st", SC_ONE_LU
+ },
+#endif /* NST */
#if NCALS > 0
- { T_PROCESSOR,T_FIXED,"standard","any"
- ,"any",calsattach,"cals",SC_MORE_LUS },
-#endif NCALS
+ {
+ T_PROCESSOR, T_FIXED, "standard", "any"
+ ,"any", calsattach, "cals", SC_MORE_LUS
+ },
+#endif /* NCALS */
#if NCH > 0
- { T_CHANGER,T_REMOV,"standard","any"
- ,"any",chattach,"ch",SC_ONE_LU },
-#endif NCH
+ {
+ T_CHANGER, T_REMOV, "standard", "any"
+ ,"any", chattach, "ch", SC_ONE_LU
+ },
+#endif /* NCH */
#if NCD > 0
- { T_READONLY,T_REMOV,"SONY ","CD-ROM CDU-8012 "
- ,"3.1a",cdattach,"cd",SC_ONE_LU },
- { T_READONLY,T_REMOV,"PIONEER ","CD-ROM DRM-600 "
- ,"any",cdattach,"cd",SC_MORE_LUS },
-#endif NCD
+#ifndef UKTEST /* make cdroms unrecognised to test the uk driver */
+ {
+ T_READONLY, T_REMOV, "SONY ", "CD-ROM CDU-8012 "
+ ,"3.1a", cdattach, "cd", SC_ONE_LU
+ },
+ {
+ T_READONLY, T_REMOV, "PIONEER ", "CD-ROM DRM-600 "
+ ,"any", cdattach, "cd", SC_MORE_LUS
+ },
+#endif
+#endif /* NCD */
#if NBLL > 0
- { T_PROCESSOR,T_FIXED,"AEG ","READER "
- ,"V1.0",bllattach,"bll",SC_MORE_LUS },
-#endif NBLL
+ {
+ T_PROCESSOR, T_FIXED, "AEG ", "READER "
+ ,"V1.0", bllattach, "bll", SC_MORE_LUS
+ },
+#endif /* NBLL */
#if NKIL > 0
- { T_SCANNER,T_FIXED,"KODAK ","IL Scanner 900 "
- ,"any",kil_attach,"kil",SC_ONE_LU },
-#endif NKIL
+ {
+ T_SCANNER, T_FIXED, "KODAK ", "IL Scanner 900 "
+ ,"any", kil_attach, "kil", SC_ONE_LU
+ },
+#endif /* NKIL */
-{0}
+ {
+ 0
+ }
};
-/***************************************************************\
-* Declarations *
-\***************************************************************/
-struct predefined *scsi_get_predef();
-struct scsidevs *scsi_probedev();
-struct scsidevs *selectdev();
-
-/* controls debug level within the scsi subsystem */
-/* see scsiconf.h for values */
-int scsi_debug = 0x0;
-int scsibus = 0x0; /* This is the Nth scsibus */
-
-/***************************************************************\
-* The routine called by the adapter boards to get all their *
-* devices configured in. *
-\***************************************************************/
-scsi_attachdevs( unit, scsi_addr, scsi_switch)
-int unit,scsi_addr;
-struct scsi_switch *scsi_switch;
+
+/*
+ * Declarations
+ */
+struct predefined *scsi_get_predef();
+struct scsidevs *scsi_probedev();
+struct scsidevs *selectdev();
+errval scsi_probe_bus __P((int bus, int targ, int lun));
+
+struct scsi_device probe_switch =
{
- int targ,lun;
- struct scsidevs *bestmatch = (struct scsidevs *)0;
- struct predefined *predef;
- int maybe_more;
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "probe",
+ 0,
+ { 0, 0 }
+};
-#ifdef SCSI_DELAY
-#if SCSI_DELAY > 2
+/*
+ * controls debug level within the scsi subsystem -
+ * see scsiconf.h for values
+ */
+int32 scsibus = 0x0; /* This is the Nth scsibus we've seen */
+
+/*
+ * The routine called by the adapter boards to get all their
+ * devices configured in.
+ */
+void
+scsi_attachdevs(sc_link_proto)
+ struct scsi_link *sc_link_proto;
+{
+
+ if(scsibus >= NSCBUS) {
+ printf("too many scsi busses, reconfigure the kernel\n");
+ return;
+ }
+ sc_link_proto->scsibus = scsibus;
+ scbus_data[scsibus] = malloc(sizeof(struct scsibus_data), M_TEMP, M_NOWAIT);
+ if(!scbus_data[scsibus]) {
+ panic("scsi_attachdevs: malloc\n");
+ }
+ bzero(scbus_data[scsibus], sizeof(struct scsibus_data));
+ scbus_data[scsibus]->adapter_link = sc_link_proto;
+#if defined(SCSI_DELAY) && SCSI_DELAY > 2
printf("%s%d waiting for scsi devices to settle\n",
- scsi_switch->name, unit);
-#else SCSI_DELAY > 2
-#define SCSI_DELAY 2
-#endif SCSI_DELAY > 2
-#else
+ sc_link_proto->adapter->name, sc_link_proto->adapter_unit);
+#else /* SCSI_DELAY > 2 */
+#undef SCSI_DELAY
#define SCSI_DELAY 2
-#endif SCSI_DELAY
- spinwait(1000 * SCSI_DELAY);
- targ = 0;
- while(targ < 8)
- {
- maybe_more = 0; /* by default only check 1 lun */
- if (targ == scsi_addr)
- {
- targ++;
+#endif /* SCSI_DELAY */
+ DELAY(1000000 * SCSI_DELAY);
+ scsibus++;
+ scsi_probe_bus(scsibus - 1,-1,-1);
+}
+
+/*
+ * Probe the requested scsi bus. It must be already set up.
+ * -1 requests all set up scsi busses.
+ * targ and lun optionally narrow the search if not -1
+ */
+errval
+scsi_probe_busses(int bus, int targ, int lun)
+{
+ if (bus == -1) {
+ for(bus = 0; bus < scsibus; bus++) {
+ scsi_probe_bus(bus, targ, lun);
+ }
+ return 0;
+ } else {
+ return scsi_probe_bus(bus, targ, lun);
+ }
+}
+
+/*
+ * Probe the requested scsi bus. It must be already set up.
+ * targ and lun optionally narrow the search if not -1
+ */
+errval
+scsi_probe_bus(int bus, int targ, int lun)
+{
+ struct scsibus_data *scsi ;
+ int maxtarg,mintarg,maxlun,minlun;
+ struct scsi_link *sc_link_proto;
+ u_int8 scsi_addr ;
+ struct scsidevs *bestmatch = NULL;
+ struct predefined *predef = NULL;
+ struct scsi_link *sc_link = NULL;
+ boolean maybe_more;
+
+ if ((bus < 0 ) || ( bus >= scsibus)) {
+ return ENXIO;
+ }
+ scsi = scbus_data[bus];
+ if(!scsi) return ENXIO;
+ sc_link_proto = scsi->adapter_link;
+ scsi_addr = sc_link_proto->adapter_targ;
+ if(targ == -1){
+ maxtarg = 7;
+ mintarg = 0;
+ } else {
+ if((targ < 0 ) || (targ > 7)) return EINVAL;
+ maxtarg = mintarg = targ;
+ }
+
+ if(lun == -1){
+ maxlun = 7;
+ minlun = 0;
+ } else {
+ if((lun < 0 ) || (lun > 7)) return EINVAL;
+ maxlun = minlun = lun;
+ }
+
+
+ for ( targ = mintarg;targ <= maxtarg; targ++) {
+ maybe_more = 0; /* by default only check 1 lun */
+ if (targ == scsi_addr) {
continue;
}
- lun = 0;
- while(lun < 8)
- {
- predef = scsi_get_predef(scsibus
- ,targ
- ,lun
- ,scsi_switch
- ,&maybe_more);
- bestmatch = scsi_probedev(unit
- ,targ
- ,lun
- ,scsi_switch
- ,&maybe_more);
- if((bestmatch) && (predef)) /* both exist */
- {
- if(bestmatch->attach_rtn
- != predef->attach_rtn)
- {
- printf("Clash in found/expected devices\n");
- printf("will link in FOUND\n");
+ for ( lun = minlun; lun <= maxlun ;lun++) {
+ /*
+ * The spot appears to already have something
+ * linked in, skip past it. Must be doing a 'reprobe'
+ */
+ if(scsi->sc_link[targ][lun])
+ {/* don't do this one, but check other luns */
+ maybe_more = 1;
+ continue;
+ }
+ /*
+ * If we presently don't have a link block
+ * then allocate one to use while probing
+ */
+ if (!sc_link) {
+ sc_link = malloc(sizeof(*sc_link), M_TEMP, M_NOWAIT);
+ *sc_link = *sc_link_proto; /* struct copy */
+ sc_link->opennings = 1;
+ sc_link->device = &probe_switch;
+ }
+ sc_link->target = targ;
+ sc_link->lun = lun;
+ predef = scsi_get_predef(sc_link, &maybe_more);
+ bestmatch = scsi_probedev(sc_link, &maybe_more);
+ if ((bestmatch) && (predef)) { /* both exist */
+ if (bestmatch->attach_rtn
+ != predef->attach_rtn) {
+ printf("Clash in found/expected devices\n");
+#if NUK > 0
+ if(bestmatch == &unknowndev) {
+ printf("will link in PREDEFINED\n");
+ (*(predef->attach_rtn)) (sc_link);
+ } else
+#endif /*NUK*/
+ {
+ printf("will link in FOUND\n");
+ (*(bestmatch->attach_rtn)) (sc_link);
+ }
+ } else {
+ (*(bestmatch->attach_rtn)) (sc_link);
}
- (*(bestmatch->attach_rtn))(unit,
- targ,
- lun,
- scsi_switch);
}
- if((bestmatch) && (!predef)) /* just FOUND */
- {
- (*(bestmatch->attach_rtn))(unit,
- targ,
- lun,
- scsi_switch);
+ if ((bestmatch) && (!predef)) { /* just FOUND */
+ (*(bestmatch->attach_rtn)) (sc_link);
}
- if((!bestmatch) && (predef)) /* just predef */
- {
- (*(predef->attach_rtn))(unit,
- targ,
- lun,
- scsi_switch);
+ if ((!bestmatch) && (predef)) { /* just predef */
+ (*(predef->attach_rtn)) (sc_link);
}
- if(!(maybe_more)) /* nothing suggests we'll find more */
- {
+ if ((bestmatch) || (predef)) { /* one exists */
+ scsi->sc_link[targ][lun] = sc_link;
+ sc_link = NULL; /* it's been used */
+ }
+ if (!(maybe_more)) { /* nothing suggests we'll find more */
break; /* nothing here, skip to next targ */
}
- /* otherwise something says we should look further*/
- lun++;
+ /* otherwise something says we should look further */
}
- targ++;
}
-#if NSG > 0
- /***************************************************************\
- * If available hook up the generic scsi driver, letting it *
- * know which target is US. (i.e. illegal or at least special) *
- \***************************************************************/
- sg_attach(unit,scsi_addr,scsi_switch);
-#endif
- scsibus++; /* next time we are on the NEXT scsi bus */
+ if (sc_link) {
+ free(sc_link, M_TEMP);
+ }
+ return 0;
}
-/***********************************************\
-* given a target and lu, check if there is a *
-* predefined device for that address *
-\***********************************************/
-struct predefined *scsi_get_predef(unit,target,lu,scsi_switch,maybe_more)
-int unit,target,lu,*maybe_more;
-struct scsi_switch *scsi_switch;
+/*
+ * given a target and lu, check if there is a predefined device for
+ * that address
+ */
+struct predefined *
+scsi_get_predef(sc_link, maybe_more)
+ struct scsi_link *sc_link;
+ boolean *maybe_more;
{
- int upto,numents;
+ u_int8 unit = sc_link->scsibus;
+ u_int8 target = sc_link->target;
+ u_int8 lu = sc_link->lun;
+ struct scsi_adapter *scsi_adapter = sc_link->adapter;
+ u_int32 upto, numents;
- numents = (sizeof(pd)/sizeof(struct predefined)) - 1;
-
- for(upto = 0;upto < numents;upto++)
- {
- if(pd[upto].scsibus != unit)
+ numents = (sizeof(pd) / sizeof(struct predefined)) - 1;
+
+ for (upto = 0; upto < numents; upto++) {
+ if (pd[upto].scsibus != unit)
continue;
- if(pd[upto].dev != target)
+ if (pd[upto].dev != target)
continue;
- if(pd[upto].lu != lu)
+ if (pd[upto].lu != lu)
continue;
-
+
printf("%s%d targ %d lun %d: <%s> - PRECONFIGURED -\n"
- ,scsi_switch->name
- ,unit
- ,target
- ,lu
- ,pd[upto].devname);
+ ,scsi_adapter->name
+ ,unit
+ ,target
+ ,lu
+ ,pd[upto].devname);
*maybe_more = pd[upto].flags & SC_MORE_LUS;
- return(&(pd[upto]));
+ return (&(pd[upto]));
}
- return((struct predefined *)0);
+ return ((struct predefined *) 0);
}
-/***********************************************\
-* given a target and lu, ask the device what *
-* it is, and find the correct driver table *
-* entry. *
-\***********************************************/
-struct scsidevs *scsi_probedev(unit,target,lu,scsi_switch, maybe_more)
-
-struct scsi_switch *scsi_switch;
-int unit,target,lu;
-int *maybe_more;
+/*
+ * given a target and lu, ask the device what
+ * it is, and find the correct driver table
+ * entry.
+ */
+struct scsidevs *
+scsi_probedev(sc_link, maybe_more)
+ boolean *maybe_more;
+ struct scsi_link *sc_link;
{
- struct scsidevs *bestmatch = (struct scsidevs *)0;
- char *dtype=(char *)0,*desc;
- char *qtype;
- static struct scsi_inquiry_data inqbuf;
- int len,qualifier,type,remov;
- char manu[32];
- char model[32];
- char version[32];
-
-
- bzero(&inqbuf,sizeof(inqbuf));
- /***********************************************\
- * Ask the device what it is *
- \***********************************************/
-#ifdef DEBUG
- if((target == 0) && (lu == 0))
- scsi_debug = 0xfff;
+ u_int8 unit = sc_link->adapter_unit;
+ u_int8 target = sc_link->target;
+ u_int8 lu = sc_link->lun;
+ struct scsi_adapter *scsi_adapter = sc_link->adapter;
+ struct scsidevs *bestmatch = (struct scsidevs *) 0;
+ char *dtype = (char *) 0, *desc;
+ char *qtype;
+ static struct scsi_inquiry_data inqbuf;
+ u_int32 len, qualifier, type;
+ boolean remov;
+ char manu[32];
+ char model[32];
+ char version[32];
+
+ bzero(&inqbuf, sizeof(inqbuf));
+ /*
+ * Ask the device what it is
+ */
+#ifdef SCSIDEBUG
+ if ((target == DEBUGTARG) && (lu == DEBUGLUN))
+ sc_link->flags |= (DEBUGLEVEL);
else
- scsi_debug = 0;
-#endif DEBUG
- if(scsi_ready( unit,
- target,
- lu,
- scsi_switch,
- SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
- {
- return(struct scsidevs *)0;
- }
- if(scsi_inquire(unit,
- target,
- lu,
- scsi_switch,
- &inqbuf,
- SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
- {
- return(struct scsidevs *)0;
- }
+ sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2 | SDEV_DB3 | SDEV_DB4);
+#endif /* SCSIDEBUG */
+ /* catch unit attn */
+ scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
+#ifdef DOUBTFULL
+ switch (scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
+ case 0: /* said it WAS ready */
+ case EBUSY: /* replied 'NOT READY' but WAS present, continue */
+ case ENXIO:
+ break;
+ case EIO: /* device timed out */
+ case EINVAL: /* Lun not supported */
+ default:
+ return (struct scsidevs *) 0;
- /***********************************************\
- * note what BASIC type of device it is *
- \***********************************************/
- if(scsi_debug & SHOWINQUIRY)
- {
- desc=(char *)&inqbuf;
- printf("inq: %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
- desc[0], desc[1], desc[2], desc[3],
- desc[4], desc[5], desc[6], desc[7],
- desc[8], desc[9], desc[10], desc[11],
- desc[12]);
+ }
+#endif /*DOUBTFULL*/
+#ifdef SCSI_2_DEF
+ /* some devices need to be told to go to SCSI2 */
+ /* However some just explode if you tell them this.. leave it out */
+ scsi_change_def(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
+#endif /*SCSI_2_DEF */
+
+ /* Now go ask the device all about itself */
+ if (scsi_inquire(sc_link, &inqbuf, SCSI_NOSLEEP | SCSI_NOMASK) != 0) {
+ return (struct scsidevs *) 0;
}
+ /*
+ * note what BASIC type of device it is
+ */
type = inqbuf.device & SID_TYPE;
qualifier = inqbuf.device & SID_QUAL;
remov = inqbuf.dev_qual2 & SID_REMOVABLE;
-
- /* Any device qualifier that has
- * the top bit set (qualifier&4 != 0) is vendor specific and
- * won't match in this switch.
+ /*
+ * Any device qualifier that has the top bit set (qualifier&4 != 0)
+ * is vendor specific and won't match in this switch.
*/
- switch(qualifier)
- {
+ switch (qualifier) {
case SID_QUAL_LU_OK:
- qtype="";
+ qtype = "";
break;
case SID_QUAL_LU_OFFLINE:
- qtype=", Unit not Connected!";
+ qtype = ", Unit not Connected!";
break;
case SID_QUAL_RSVD:
- qtype=", Reserved Peripheral Qualifier!";
+ qtype = ", Reserved Peripheral Qualifier!";
*maybe_more = 1;
- return (struct scsidevs *)0;
+ return (struct scsidevs *) 0;
break;
case SID_QUAL_BAD_LU:
/*
* Check for a non-existent unit. If the device is returning
- * this much, then we must set the flag that has
- * the searcher keep looking on other luns.
- */
- qtype=", The Target can't support this Unit!";
+ * this much, then we must set the flag that has
+ * the searchers keep looking on other luns.
+ */
+ qtype = ", The Target can't support this Unit!";
*maybe_more = 1;
- return (struct scsidevs *)0;
+ return (struct scsidevs *) 0;
default:
- dtype="vendor specific";
- qtype="";
+ dtype = "vendor specific";
+ qtype = "";
*maybe_more = 1;
break;
}
-
- if (dtype == 0)
- {
- switch(type)
- {
+ if (dtype == 0) {
+ switch (type) {
case T_DIRECT:
- dtype="direct";
+ dtype = "direct";
break;
case T_SEQUENTIAL:
- dtype="sequential";
+ dtype = "sequential";
break;
case T_PRINTER:
- dtype="printer";
+ dtype = "printer";
break;
case T_PROCESSOR:
- dtype="processor";
+ dtype = "processor";
break;
case T_READONLY:
- dtype="readonly";
+ dtype = "readonly";
break;
case T_WORM:
- dtype="worm";
+ dtype = "worm";
break;
case T_SCANNER:
- dtype="scanner";
+ dtype = "scanner";
break;
case T_OPTICAL:
- dtype="optical";
+ dtype = "optical";
break;
case T_CHANGER:
- dtype="changer";
+ dtype = "changer";
break;
case T_COMM:
- dtype="communication";
+ dtype = "communication";
break;
case T_NODEVICE:
*maybe_more = 1;
- return (struct scsidevs *)0;
+ return (struct scsidevs *) 0;
default:
- dtype="unknown";
+ dtype = "unknown";
break;
}
-
- }
- /***********************************************\
- * Then if it's advanced enough, more detailed *
- * information *
- \***********************************************/
- if((inqbuf.version & SID_ANSII) > 0)
- {
- if ((len = inqbuf.additional_length
- + ( (char *)inqbuf.unused
- - (char *)&inqbuf))
- > (sizeof(struct scsi_inquiry_data) - 1))
- len = sizeof(struct scsi_inquiry_data) - 1;
- desc=inqbuf.vendor;
- desc[len-(desc - (char *)&inqbuf)] = 0;
- strncpy(manu,inqbuf.vendor,8);manu[8]=0;
- strncpy(model,inqbuf.product,16);model[16]=0;
- strncpy(version,inqbuf.revision,4);version[4]=0;
}
- else
- /***********************************************\
- * If not advanced enough, use default values *
- \***********************************************/
+ /*
+ * Then if it's advanced enough, more detailed
+ * information
+ */
+ if ((inqbuf.version & SID_ANSII) > 0) {
+ if ((len = inqbuf.additional_length
+ + ((char *) inqbuf.unused
+ - (char *) &inqbuf))
+ > (sizeof(struct scsi_inquiry_data) - 1))
+ len = sizeof(struct scsi_inquiry_data) - 1;
+ desc = inqbuf.vendor;
+ desc[len - (desc - (char *) &inqbuf)] = 0;
+ strncpy(manu, inqbuf.vendor, 8);
+ manu[8] = 0;
+ strncpy(model, inqbuf.product, 16);
+ model[16] = 0;
+ strncpy(version, inqbuf.revision, 4);
+ version[4] = 0;
+ } else
+ /*
+ * If not advanced enough, use default values
+ */
{
- desc="early protocol device";
- strncpy(manu,"unknown",8);
- strncpy(model,"unknown",16);
- strncpy(version,"????",4);
+ desc = "early protocol device";
+ strncpy(manu, "unknown", 8);
+ strncpy(model, "unknown", 16);
+ strncpy(version, "????", 4);
}
printf("%s%d targ %d lun %d: type %d(%s) %s SCSI%d\n"
- ,scsi_switch->name
- ,unit
- ,target
- ,lu
- ,type
- ,dtype
- ,remov?"removable":"fixed"
- ,inqbuf.version & SID_ANSII
- );
+ ,scsi_adapter->name
+ ,unit
+ ,target
+ ,lu
+ ,type
+ ,dtype
+ ,remov ? "removable" : "fixed"
+ ,inqbuf.version & SID_ANSII
+ );
printf("%s%d targ %d lun %d: <%s%s%s>\n"
- ,scsi_switch->name
- ,unit
- ,target
- ,lu
- ,manu
- ,model
- ,version
- );
- if(qtype[0])
- {
+ ,scsi_adapter->name
+ ,unit
+ ,target
+ ,lu
+ ,manu
+ ,model
+ ,version
+ );
+ if (qtype[0]) {
printf("%s%d targ %d lun %d: qualifier %d(%s)\n"
- ,scsi_switch->name
- ,unit
- ,target
- ,lu
- ,qualifier
- ,qtype
- );
+ ,scsi_adapter->name
+ ,unit
+ ,target
+ ,lu
+ ,qualifier
+ ,qtype
+ );
}
- /***********************************************\
- * Try make as good a match as possible with *
- * available sub drivers *
- \***********************************************/
- bestmatch = (selectdev(unit,target,lu,&scsi_switch,
- qualifier,type,remov?T_REMOV:T_FIXED,manu,model,version));
- if((bestmatch) && (bestmatch->flags & SC_MORE_LUS))
- {
+ /*
+ * Try make as good a match as possible with
+ * available sub drivers
+ */
+ bestmatch = (selectdev(
+ qualifier, type, remov ? T_REMOV : T_FIXED, manu, model, version));
+ if ((bestmatch) && (bestmatch->flags & SC_MORE_LUS)) {
*maybe_more = 1;
}
- return(bestmatch);
+ return (bestmatch);
}
-
-/***********************************************\
-* Try make as good a match as possible with *
-* available sub drivers *
-\***********************************************/
-struct scsidevs
-*selectdev(unit,target,lu,dvr_switch,qualifier,type,remov,manu,model,rev)
-int unit,target,lu;
-struct scsi_switch *dvr_switch;
-int qualifier,type,remov;
-char *manu,*model,*rev;
+/*
+ * Try make as good a match as possible with
+ * available sub drivers
+ */
+struct scsidevs *
+selectdev(qualifier, type, remov, manu, model, rev)
+ u_int32 qualifier, type;
+ boolean remov;
+ char *manu, *model, *rev;
{
- int numents = (sizeof(knowndevs)/sizeof(struct scsidevs)) - 1;
- int count = 0;
- int bestmatches = 0;
- struct scsidevs *bestmatch = (struct scsidevs *)0;
- struct scsidevs *thisentry = knowndevs;
+ u_int32 numents = (sizeof(knowndevs) / sizeof(struct scsidevs)) - 1;
+ u_int32 count = 0;
+ u_int32 bestmatches = 0;
+ struct scsidevs *bestmatch = (struct scsidevs *) 0;
+ struct scsidevs *thisentry = knowndevs;
type |= qualifier; /* why? */
thisentry--;
- while( count++ < numents)
- {
+ while (count++ < numents) {
thisentry++;
- if(type != thisentry->type)
- {
+ if (type != thisentry->type) {
continue;
}
- if(bestmatches < 1)
- {
+ if (bestmatches < 1) {
bestmatches = 1;
bestmatch = thisentry;
}
- if(remov != thisentry->removable)
- {
+ if (remov != thisentry->removable) {
continue;
}
- if(bestmatches < 2)
- {
+ if (bestmatches < 2) {
bestmatches = 2;
bestmatch = thisentry;
}
- if(thisentry->flags & SC_SHOWME)
- printf("\n%s-\n%s-",thisentry->manufacturer, manu);
- if(strcmp(thisentry->manufacturer, manu))
- {
+ if (thisentry->flags & SC_SHOWME)
+ printf("\n%s-\n%s-", thisentry->manufacturer, manu);
+ if (strcmp(thisentry->manufacturer, manu)) {
continue;
}
- if(bestmatches < 3)
- {
+ if (bestmatches < 3) {
bestmatches = 3;
bestmatch = thisentry;
}
- if(thisentry->flags & SC_SHOWME)
- printf("\n%s-\n%s-",thisentry->model, model);
- if(strcmp(thisentry->model, model))
- {
+ if (thisentry->flags & SC_SHOWME)
+ printf("\n%s-\n%s-", thisentry->model, model);
+ if (strcmp(thisentry->model, model)) {
continue;
}
- if(bestmatches < 4)
- {
+ if (bestmatches < 4) {
bestmatches = 4;
bestmatch = thisentry;
}
- if(thisentry->flags & SC_SHOWME)
- printf("\n%s-\n%s-",thisentry->version, rev);
- if(strcmp(thisentry->version, rev))
- {
+ if (thisentry->flags & SC_SHOWME)
+ printf("\n%s-\n%s-", thisentry->version, rev);
+ if (strcmp(thisentry->version, rev)) {
continue;
}
- if(bestmatches < 5)
- {
+ if (bestmatches < 5) {
bestmatches = 5;
bestmatch = thisentry;
break;
}
}
-
- if (bestmatch == (struct scsidevs *)0)
- printf(" No explicit device driver match for \"%s %s\".\n",
- manu, model);
-
- return(bestmatch);
-}
-
-static int recurse = 0;
-/***********************************************\
-* Do a scsi operation asking a device if it is *
-* ready. Use the scsi_cmd routine in the switch *
-* table. *
-\***********************************************/
-scsi_ready(unit,target,lu,scsi_switch, flags)
-struct scsi_switch *scsi_switch;
-{
- struct scsi_test_unit_ready scsi_cmd;
- struct scsi_xfer scsi_xfer;
- volatile int rval;
- int key;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- bzero(&scsi_xfer, sizeof(scsi_xfer));
- scsi_cmd.op_code = TEST_UNIT_READY;
-
- scsi_xfer.flags=flags | INUSE;
- scsi_xfer.adapter=unit;
- scsi_xfer.targ=target;
- scsi_xfer.lu=lu;
- scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
- scsi_xfer.retries=8;
- scsi_xfer.timeout=10000;
- scsi_xfer.cmdlen=sizeof(scsi_cmd);
- scsi_xfer.data=0;
- scsi_xfer.datalen=0;
- scsi_xfer.resid=0;
- scsi_xfer.when_done=0;
- scsi_xfer.done_arg=0;
-retry: scsi_xfer.error=0;
- /*******************************************************\
- * do not use interrupts *
- \*******************************************************/
- rval = (*(scsi_switch->scsi_cmd))(&scsi_xfer);
- if (rval != COMPLETE)
- {
- if(scsi_debug)
- {
- printf("scsi error, rval = 0x%x\n",rval);
- printf("code from driver: 0x%x\n",scsi_xfer.error);
- }
- switch(scsi_xfer.error)
- {
- case XS_SENSE:
- /*******************************************************\
- * Any sense value is illegal except UNIT ATTENTION *
- * In which case we need to check again to get the *
- * correct response. *
- *( especially exabytes) *
- \*******************************************************/
- if(((scsi_xfer.sense.error_code & SSD_ERRCODE) == 0x70 )
- ||((scsi_xfer.sense.error_code & SSD_ERRCODE) == 0x71 ))
- {
- key = scsi_xfer.sense.ext.extended.flags & SSD_KEY ;
- switch(key)
- {
- case 2: /* not ready BUT PRESENT! */
- return(COMPLETE);
- case 6:
- spinwait(1000);
- if(scsi_xfer.retries--)
- {
- scsi_xfer.flags &= ~ITSDONE;
- goto retry;
- }
- return(COMPLETE);
- default:
- if(scsi_debug)
- printf("%d:%d,key=%x.",
- target,lu,key);
- }
- }
- return(HAD_ERROR);
- case XS_BUSY:
- spinwait(1000);
- if(scsi_xfer.retries--)
- {
- scsi_xfer.flags &= ~ITSDONE;
- goto retry;
- }
- return(COMPLETE); /* it's busy so it's there */
- case XS_TIMEOUT:
- default:
- return(HAD_ERROR);
- }
- }
- return(COMPLETE);
-}
-/***********************************************\
-* Do a scsi operation asking a device what it is*
-* Use the scsi_cmd routine in the switch table. *
-\***********************************************/
-scsi_inquire(unit,target,lu,scsi_switch,inqbuf, flags)
-struct scsi_switch *scsi_switch;
-u_char *inqbuf;
-{
- struct scsi_inquiry scsi_cmd;
- struct scsi_xfer scsi_xfer;
- volatile int rval;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- bzero(&scsi_xfer, sizeof(scsi_xfer));
- scsi_cmd.op_code = INQUIRY;
- scsi_cmd.length = sizeof(struct scsi_inquiry_data);
-
- scsi_xfer.flags=flags | SCSI_DATA_IN | INUSE;
- scsi_xfer.adapter=unit;
- scsi_xfer.targ=target;
- scsi_xfer.lu=lu;
- scsi_xfer.retries=8;
- scsi_xfer.timeout=10000;
- scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
- scsi_xfer.cmdlen= sizeof(struct scsi_inquiry);
- scsi_xfer.data=inqbuf;
- scsi_xfer.datalen=sizeof(struct scsi_inquiry_data);
- scsi_xfer.resid=sizeof(struct scsi_inquiry_data);
- scsi_xfer.when_done=0;
- scsi_xfer.done_arg=0;
-retry: scsi_xfer.error=0;
- /*******************************************************\
- * do not use interrupts *
- \*******************************************************/
- if ((*(scsi_switch->scsi_cmd))(&scsi_xfer) != COMPLETE)
- {
- if(scsi_debug) printf("inquiry had error(0x%x) ",scsi_xfer.error);
- switch(scsi_xfer.error)
- {
- case XS_NOERROR:
- break;
- case XS_SENSE:
- /*******************************************************\
- * Any sense value is illegal except UNIT ATTENTION *
- * In which case we need to check again to get the *
- * correct response. *
- *( especially exabytes) *
- \*******************************************************/
- if(((scsi_xfer.sense.error_code & SSD_ERRCODE) == 0x70 )
- && ((scsi_xfer.sense.ext.extended.flags & SSD_KEY) == 6))
- { /* it's changed so it's there */
- spinwait(1000);
- {
- if(scsi_xfer.retries--)
- {
- scsi_xfer.flags &= ~ITSDONE;
- goto retry;
- }
- }
- return( COMPLETE);
- }
- return(HAD_ERROR);
- case XS_BUSY:
- spinwait(1000);
- if(scsi_xfer.retries--)
- {
- scsi_xfer.flags &= ~ITSDONE;
- goto retry;
- }
- case XS_TIMEOUT:
- default:
- return(HAD_ERROR);
- }
+ if (bestmatch == (struct scsidevs *) 0) {
+#if NUK > 0
+ bestmatch = &unknowndev;
+#else
+ printf("No explicit device driver match.\n");
+#endif
}
- return(COMPLETE);
-}
-
-
-
-
-/***********************************************\
-* Utility routines often used in SCSI stuff *
-\***********************************************/
-
-/***********************************************\
-* convert a physical address to 3 bytes, *
-* MSB at the lowest address, *
-* LSB at the highest. *
-\***********************************************/
-
-lto3b(val, bytes)
-u_char *bytes;
-{
- *bytes++ = (val&0xff0000)>>16;
- *bytes++ = (val&0xff00)>>8;
- *bytes = val&0xff;
+ return (bestmatch);
}
-
-/***********************************************\
-* The reverse of lto3b *
-\***********************************************/
-_3btol(bytes)
-u_char *bytes;
-{
- int rc;
- rc = (*bytes++ << 16);
- rc += (*bytes++ << 8);
- rc += *bytes;
- return(rc);
-}
-
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index 5738de5..856fe89 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -14,88 +14,179 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsiconf.h,v 1.5 1993/08/28 03:08:54 rgrimes Exp $
+ * $Id: scsiconf.h,v 2.4 93/10/16 00:59:13 julian Exp Locker: julian $
*/
+#ifndef SCSI_SCSICONF_H
+#define SCSI_SCSICONF_H 1
+typedef int boolean;
+typedef int errval;
+typedef long int int32;
+typedef short int int16;
+typedef char int8;
+typedef unsigned long int u_int32;
+typedef unsigned short int u_int16;
+typedef unsigned char u_int8;
-#ifndef _SCSI_SCSICONF_H_
-#define _SCSI_SCSICONF_H_ 1
+#include <scsi/scsi_debug.h>
-/***********************************************\
-* these calls are called by the high-end *
-* drivers to get services from whatever low-end *
-* drivers they are attached to *
-\***********************************************/
-struct scsi_switch
+/*
+ * The following documentation tries to describe the relationship between the
+ * various structures defined in this file:
+ *
+ * each adapter type has a scsi_adapter struct. This describes the adapter and
+ * identifies routines that can be called to use the adapter.
+ * each device type has a scsi_device struct. This describes the device and
+ * identifies routines that can be called to use the device.
+ * each existing device position (scsibus + target + lun)
+ * can be described by a scsi_link struct.
+ * Only scsi positions that actually have devices, have a scsi_link
+ * structure assigned. so in effect each device has scsi_link struct.
+ * The scsi_link structure contains information identifying both the
+ * device driver and the adapter driver for that position on that scsi bus,
+ * and can be said to 'link' the two.
+ * each individual scsi bus has an array that points to all the scsi_link
+ * structs associated with that scsi bus. Slots with no device have
+ * a NULL pointer.
+ * each individual device also knows the address of it's own scsi_link
+ * structure.
+ *
+ * -------------
+ *
+ * The key to all this is the scsi_link structure which associates all the
+ * other structures with each other in the correct configuration. The
+ * scsi_link is the connecting information that allows each part of the
+ * scsi system to find the associated other parts.
+ */
+
+
+/*
+ * These entrypoints are called by the high-end drivers to get services from
+ * whatever low-end drivers they are attached to each adapter type has one of
+ * these statically allocated.
+ */
+struct scsi_adapter
{
- int (*scsi_cmd)();
- void (*scsi_minphys)();
- int (*open_target_lu)();
- int (*close_target_lu)();
- long int (*adapter_info)(); /* see definitions below */
- char *name; /* name of scsi bus controller */
- u_long spare[2];
+/* 04*/ int32 (*scsi_cmd)();
+/* 08*/ void (*scsi_minphys)();
+/* 12*/ int32 (*open_target_lu)();
+/* 16*/ int32 (*close_target_lu)();
+/* 20*/ u_int32 (*adapter_info)(); /* see definitions below */
+/* 24*/ char *name; /* name of scsi bus controller */
+/* 32*/ u_long spare[2];
};
-#define AD_INF_MAX_CMDS 0x000000FF /* maximum number of entries
- queuable to a device by
- the adapter */
-/* 24 bits of other adapter characteristics go here */
-/***********************************************\
-* The scsi debug control bits *
-\***********************************************/
-extern int scsi_debug;
-#define PRINTROUTINES 0x01
-#define TRACEOPENS 0x02
-#define TRACEINTERRUPTS 0x04
-#define SHOWREQUESTS 0x08
-#define SHOWSCATGATH 0x10
-#define SHOWINQUIRY 0x20
-#define SHOWCOMMANDS 0x40
-
-
-/********************************/
-/* return values for scsi_cmd() */
-/********************************/
+/*
+ * return values for scsi_cmd()
+ */
#define SUCCESSFULLY_QUEUED 0
#define TRY_AGAIN_LATER 1
#define COMPLETE 2
-#define HAD_ERROR 3
+#define HAD_ERROR 3 /* do not use this, use COMPLETE */
#define ESCAPE_NOT_SUPPORTED 4
+/*
+ * Format of adapter_info() response data
+ * e.g. maximum number of entries queuable to a device by the adapter
+ */
+#define AD_INF_MAX_CMDS 0x000000FF
+/* 24 bits of other adapter characteristics go here */
+
+/*
+ * These entry points are called by the low-end drivers to get services from
+ * whatever high-end drivers they are attached to. Each device type has one
+ * of these statically allocated.
+ */
+struct scsi_device
+{
+/* 4*/ errval (*err_handler)(); /* returns -1 to say err processing complete */
+/* 8*/ void (*start)();
+/* 12*/ int32 (*async)();
+/* 16*/ int32 (*done)(); /* returns -1 to say done processing complete */
+/* 20*/ char *name; /* name of device type */
+/* 24*/ u_int32 flags; /* device type dependent flags */
+/* 32*/ int32 spare[2];
+};
+
+/*
+ * This structure describes the connection between an adapter driver and
+ * a device driver, and is used by each to call services provided by
+ * the other, and to allow generic scsi glue code to call these services
+ * as well.
+ */
+struct scsi_link
+{
+/* 1*/ u_int8 target; /* targ of this dev */
+/* 2*/ u_int8 lun; /* lun of this dev */
+/* 3*/ u_int8 adapter_targ; /* what are we on the scsi bus */
+/* 4*/ u_int8 adapter_unit; /* e.g. the 0 in aha0 */
+/* 5*/ u_int8 scsibus; /* the Nth scsibus */
+/* 6*/ u_int8 dev_unit; /* e.g. the 0 in sd0 */
+/* 7*/ u_int8 opennings; /* available operations */
+/* 8*/ u_int8 active; /* operations in progress */
+/* 10*/ u_int16 flags; /* flags that all devices have */
+/* 12*/ u_int8 spareb[2]; /* unused */
+/* 16*/ struct scsi_adapter *adapter; /* adapter entry points etc. */
+/* 20*/ struct scsi_device *device; /* device entry points etc. */
+/* 24*/ struct scsi_xfer *active_xs; /* operations under way */
+/* 28*/ void * fordriver; /* for private use by the driver */
+/* 32*/ u_int32 spare;
+};
+#define SDEV_MEDIA_LOADED 0x01 /* device figures are still valid */
+#define SDEV_WAITING 0x02 /* a process is waiting for this */
+#define SDEV_OPEN 0x04 /* at least 1 open session */
+#define SDEV_DBX 0xF0 /* debuging flags (scsi_debug.h) */
+
+/*
+ * One of these is allocated and filled in for each scsi bus.
+ * it holds pointers to allow the scsi bus to get to the driver
+ * That is running each LUN on the bus
+ * it also has a template entry which is the prototype struct
+ * supplied by the adapter driver, this is used to initialise
+ * the others, before they have the rest of the fields filled in
+ */
+struct scsibus_data {
+ struct scsi_link *adapter_link; /* prototype supplied by adapter */
+ struct scsi_link *sc_link[8][8];
+};
+
+/*
+ * Each scsi transaction is fully described by one of these structures
+ * It includes information about the source of the command and also the
+ * device and adapter for which the command is destined.
+ * (via the scsi_link structure) *
+ */
struct scsi_xfer
{
- struct scsi_xfer *next; /* when free */
- int flags;
- u_char adapter;
- u_char targ;
- u_char lu;
- u_char retries; /* the number of times to retry */
- long int timeout; /* in miliseconds */
- struct scsi_generic *cmd;
- int cmdlen;
- u_char *data; /* either the dma address OR a uio address */
- int datalen; /* data len (blank if uio) */
- int resid;
- int (*when_done)();
- int done_arg;
- int done_arg2;
- int error;
- struct buf *bp;
- struct scsi_sense_data sense;
-
- /* Believe it or not, Some targets fall on the ground with
+/*04*/ struct scsi_xfer *next; /* when free */
+/*08*/ u_int32 flags;
+/*12*/ struct scsi_link *sc_link; /* all about our device and adapter */
+/*13*/ u_int8 retries; /* the number of times to retry */
+/*16*/ u_int8 spare[3];
+/*20*/ int32 timeout; /* in milliseconds */
+/*24*/ struct scsi_generic *cmd; /* The scsi command to execute */
+/*28*/ int32 cmdlen; /* how long it is */
+/*32*/ u_char *data; /* dma address OR a uio address */
+/*36*/ int32 datalen; /* data len (blank if uio) */
+/*40*/ int32 resid; /* how much buffer was not touched */
+/*44*/ int32 error; /* an error value */
+/*48*/ struct buf *bp; /* If we need to associate with a buf */
+/*80*/ struct scsi_sense_data sense; /* 32 bytes*/
+ /*
+ * Believe it or not, Some targets fall on the ground with
* anything but a certain sense length.
*/
- int req_sense_length; /* Explicit request sense length */
-
- int status; /* SCSI status */
+/*84*/ int32 req_sense_length; /* Explicit request sense length */
+/*88*/ int32 status; /* SCSI status */
+/*100*/ struct scsi_generic cmdstore; /* stash the command in here */
};
-/********************************/
-/* Flag values */
-/********************************/
+
+/*
+ * Per-request Flag values
+ */
#define SCSI_NOSLEEP 0x01 /* Not a user... don't sleep */
#define SCSI_NOMASK 0x02 /* dont allow interrupts.. booting */
#define SCSI_NOSTART 0x04 /* left over from ancient history */
+#define SCSI_USER 0x08 /* Is a user cmd, call scsi_user_done */
#define ITSDONE 0x10 /* the transfer is as done as it gets */
#define INUSE 0x20 /* The scsi_xfer block is in use */
#define SCSI_SILENT 0x40 /* Don't report errors to console */
@@ -107,18 +198,18 @@ struct scsi_xfer
#define SCSI_TARGET 0x1000 /* This defines a TARGET mode op. */
#define SCSI_ESCAPE 0x2000 /* Escape operation */
-/*************************************************************************/
-/* Escape op codes. This provides an extensible setup for operations */
-/* that are not scsi commands. They are intended for modal operations. */
-/*************************************************************************/
+/*
+ * Escape op codes. This provides an extensible setup for operations
+ * that are not scsi commands. They are intended for modal operations.
+ */
#define SCSI_OP_TARGET 0x0001
#define SCSI_OP_RESET 0x0002
#define SCSI_OP_BDINFO 0x0003
-/********************************/
-/* Error values */
-/********************************/
+/*
+ * Error values an adapter driver may return
+ */
#define XS_NOERROR 0x0 /* there is no error, (sense is invalid) */
#define XS_SENSE 0x1 /* Check the returned sense for the error */
#define XS_DRIVER_STUFFUP 0x2 /* Driver failed to perform operation */
@@ -126,4 +217,30 @@ struct scsi_xfer
#define XS_SWTIMEOUT 0x04 /* The Timeout reported was caught by SW */
#define XS_BUSY 0x08 /* The device busy, try again later? */
-#endif /* _SCSI_SCSICONF_H_ */
+void scsi_attachdevs __P((struct scsi_link *sc_link_proto));
+struct scsi_xfer *get_xs( struct scsi_link *sc_link, u_int32 flags);
+void free_xs(struct scsi_xfer *xs, struct scsi_link *sc_link,u_int32 flags);
+u_int32 scsi_size( struct scsi_link *sc_link,u_int32 flags);
+errval scsi_test_unit_ready( struct scsi_link *sc_link, u_int32 flags);
+errval scsi_change_def( struct scsi_link *sc_link, u_int32 flags);
+errval scsi_inquire( struct scsi_link *sc_link,
+ struct scsi_inquiry_data *inqbuf, u_int32 flags);
+errval scsi_prevent( struct scsi_link *sc_link, u_int32 type,u_int32 flags);
+errval scsi_start_unit( struct scsi_link *sc_link, u_int32 flags);
+void scsi_done(struct scsi_xfer *xs);
+errval scsi_scsi_cmd( struct scsi_link *sc_link, struct scsi_generic *scsi_cmd,
+ u_int32 cmdlen, u_char *data_addr,
+ u_int32 datalen, u_int32 retries,
+ u_int32 timeout, struct buf *bp,
+ u_int32 flags);
+errval scsi_do_ioctl __P((struct scsi_link *sc_link, int cmd, caddr_t addr, int f));
+
+void show_scsi_xs(struct scsi_xfer *xs);
+void show_scsi_cmd(struct scsi_xfer *xs);
+void show_mem(unsigned char * , u_int32);
+
+void lto3b __P((int val, u_char *bytes));
+int _3btol __P((u_char *bytes));
+
+#endif /*SCSI_SCSICONF_H*/
+/* END OF FILE */
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
index 6717449..b3320aa3 100644
--- a/sys/scsi/sd.c
+++ b/sys/scsi/sd.c
@@ -14,7 +14,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992
*
- * $Id: sd.c,v 1.10 1993/09/20 06:28:13 rgrimes Exp $
+ * $Id: sd.c,v 2.7 93/10/24 12:44:40 julian Exp Locker: julian $
*/
#define SPLSD splbio
@@ -37,20 +37,26 @@
#include <scsi/scsi_disk.h>
#include <scsi/scsiconf.h>
-long int sdstrats,sdqueues;
-
+u_int32 sdstrats, sdqueues;
+#ifdef NetBSD
+#ifdef DDB
+int Debugger();
+#else /* DDB */
+#define Debugger()
+#endif /* DDB */
+#else /* NetBSD */
#include <ddb.h>
#if NDDB > 0
-int Debugger();
-#else NDDB > 0
+int Debugger();
+#else /* NDDB > 0 */
#define Debugger()
-#endif NDDB > 0
-
+#endif /* NDDB > 0 */
+#endif
#define PAGESIZ 4096
#define SECSIZE 512
-#define PDLOCATION 29
+#define PDLOCATION 29
#define BOOTRECORDSIGNATURE (0x55aa & 0x00ff)
#define SDOUTSTANDING 2
#define SDQSIZE 4
@@ -64,838 +70,704 @@ int Debugger();
#define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAW_PART )
-struct buf sd_buf_queue[NSD];
-int sd_done();
-int sdstrategy();
+errval sdgetdisklabel __P((unsigned char unit));
+errval sd_get_parms __P((int unit, int flags));
+errval sdstrategy();
+void sdstart();
-#ifdef SDDEBUG
-int sd_debug = 0;
-#endif /*SDDEBUG*/
-
-struct scsi_xfer *sd_free_xfer[NSD];
-int sd_xfer_block_wait[NSD];
-
-struct sd_data
+struct scsi_device sd_switch =
{
- int flags;
-#define SDVALID 0x02 /* PARAMS LOADED */
-#define SDINIT 0x04 /* device has been init'd */
-#define SDWAIT 0x08 /* device has someone waiting */
-#define SDHAVELABEL 0x10 /* have read the label */
-#define SDDOSPART 0x20 /* Have read the DOS partition table */
-#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W)*/
- struct scsi_switch *sc_sw; /* address of scsi low level switch */
- int ctlr; /* so they know which one we want */
- int targ; /* our scsi target ID */
- int lu; /* out scsi lu */
- long int ad_info; /* info about the adapter */
- int cmdscount; /* cmds allowed outstanding by board*/
- int wlabel; /* label is writable */
- struct disk_parms
- {
- u_char heads; /* Number of heads */
- u_short cyls; /* Number of cylinders */
- u_char sectors;/*dubious*/ /* Number of sectors/track */
- u_short secsiz; /* Number of bytes/sector */
- u_long disksize; /* total number sectors */
- }params;
- struct disklabel disklabel;
- struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */
- int partflags[MAXPARTITIONS]; /* per partition flags */
+ NULL, /* Use default error handler */
+ sdstart, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "sd",
+ 0,
+ { 0, 0 }
+};
+
+struct sd_data {
+ u_int32 flags;
+#define SDINIT 0x04 /* device has been init'd */
+#define SDHAVELABEL 0x10 /* have read the label */
+#define SDDOSPART 0x20 /* Have read the DOS partition table */
+#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W) */
+ struct scsi_link *sc_link; /* contains our targ, lun etc. */
+ u_int32 ad_info; /* info about the adapter */
+ u_int32 cmdscount; /* cmds allowed outstanding by board */
+ boolean wlabel; /* label is writable */
+ struct disk_parms {
+ u_char heads; /* Number of heads */
+ u_int16 cyls; /* Number of cylinders */
+ u_char sectors; /*dubious *//* Number of sectors/track */
+ u_int16 secsiz; /* Number of bytes/sector */
+ u_int32 disksize; /* total number sectors */
+ } params;
+ struct disklabel disklabel;
+#ifdef NetBSD
+ struct cpu_disklabel cpudisklabel;
+#else
+ struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */
+#endif /* NetBSD */
+ u_int32 partflags[MAXPARTITIONS]; /* per partition flags */
#define SDOPEN 0x01
- int openparts; /* one bit for each open partition */
- unsigned int sd_start_of_unix; /* unix vs dos partitions */
-}*sd_data[NSD];
+ u_int32 openparts; /* one bit for each open partition */
+ u_int32 sd_start_of_unix; /* unix vs dos partitions */
+ struct buf buf_queue;
+ u_int32 xfer_block_wait;
+} *sd_data[NSD];
+static u_int32 next_sd_unit = 0;
-static int next_sd_unit = 0;
-/***********************************************************************\
-* The routine called by the low level scsi routine when it discovers *
-* A device suitable for this driver *
-\***********************************************************************/
-
-int sdattach(ctlr,targ,lu,scsi_switch)
-struct scsi_switch *scsi_switch;
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * a device suitable for this driver.
+ */
+errval
+sdattach(sc_link)
+ struct scsi_link *sc_link;
{
- int unit,i;
- unsigned char *tbl;
+ u_int32 unit;
struct sd_data *sd;
struct disk_parms *dp;
- long int ad_info;
- struct scsi_xfer *sd_scsi_xfer;
unit = next_sd_unit++;
-#ifdef SDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("sdattach: ");
-#endif /*SDDEBUG*/
- /*******************************************************\
- * Check we have the resources for another drive *
- \*******************************************************/
- if( unit >= NSD)
- {
- printf("Too many scsi disks..(%d > %d) reconfigure kernel\n",(unit + 1),NSD);
- return(0);
+ SC_DEBUG(sc_link, SDEV_DB2, ("sdattach: "));
+ /*
+ * Check we have the resources for another drive
+ */
+ if (unit >= NSD) {
+ printf("Too many scsi disks..(%d > %d) reconfigure kernel\n",
+ (unit + 1), NSD);
+ return 0;
}
- if(sd_data[unit])
- {
- printf("sd%d: unit already has storage allocated!\n",unit);
- return(0);
+ if (sd_data[unit]) {
+ printf("sd%d: unit already has storage allocated!\n", unit);
+ return 0;
}
- sd = sd_data[unit] = malloc(sizeof(struct sd_data),M_DEVBUF,M_NOWAIT);
- if(!sd)
- {
+ sd = sd_data[unit] = malloc(sizeof(struct sd_data), M_DEVBUF, M_NOWAIT);
+ if (!sd) {
printf("malloc failed in sd.c\n");
- return(0);
+ return (0);
}
- bzero(sd,sizeof(struct sd_data));
-
- dp = &(sd->params);
- /*******************************************************\
- * Store information needed to contact our base driver *
- \*******************************************************/
- sd->sc_sw = scsi_switch;
- sd->ctlr = ctlr;
- sd->targ = targ;
- sd->lu = lu;
- if(sd->sc_sw->adapter_info)
- {
- sd->ad_info = ( (*(sd->sc_sw->adapter_info))(ctlr));
- sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS;
- if(sd->cmdscount > SDOUTSTANDING)
- {
+ bzero(sd, sizeof(struct sd_data));
+
+ dp = &(sd->params);
+ /*
+ * Store information needed to contact our base driver
+ */
+ sd->sc_link = sc_link;
+ sc_link->device = &sd_switch;
+ sc_link->dev_unit = unit;
+
+ if (sd->sc_link->adapter->adapter_info) {
+ sd->ad_info = ((*(sd->sc_link->adapter->adapter_info)) (sc_link->adapter_unit));
+ sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS;
+ if (sd->cmdscount > SDOUTSTANDING) {
sd->cmdscount = SDOUTSTANDING;
}
- }
- else
- {
+ } else {
sd->ad_info = 1;
- sd->cmdscount = 1;
- }
-
- i = sd->cmdscount;
- sd_scsi_xfer = (struct scsi_xfer *)malloc(sizeof(struct scsi_xfer) * i
- ,M_TEMP, M_NOWAIT);
- while(i-- )
- {
- sd_scsi_xfer->next = sd_free_xfer[unit];
- sd_free_xfer[unit] = sd_scsi_xfer;
- sd_scsi_xfer++;
- }
- /*******************************************************\
- * Use the subdriver to request information regarding *
- * the drive. We cannot use interrupts yet, so the *
- * request must specify this. *
- \*******************************************************/
- sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
+ sd->cmdscount = 1;
+ }
+ sc_link->opennings = sd->cmdscount;
+ /*
+ * Use the subdriver to request information regarding
+ * the drive. We cannot use interrupts yet, so the
+ * request must specify this.
+ */
+ sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
printf("sd%d: %dMB (%d total sec), %d cyl, %d head, %d sec, bytes/sec %d\n",
- unit,
- dp->disksize / ((1024L * 1024L) / dp->secsiz),
- dp->disksize,
- dp->cyls,
- dp->heads,
- dp->sectors,
- dp->secsiz);
+ unit,
+ dp->disksize / ((1024L * 1024L) / dp->secsiz),
+ dp->disksize,
+ dp->cyls,
+ dp->heads,
+ dp->sectors,
+ dp->secsiz);
sd->flags |= SDINIT;
- return;
-
+ return 0;
}
-
-
-/*******************************************************\
-* open the device. Make sure the partition info *
-* is a up-to-date as can be. *
-\*******************************************************/
+/*
+ * open the device. Make sure the partition info is a up-to-date as can be.
+ */
+errval
sdopen(dev)
+ int dev; /* XXX should be dev_t, but avoid promotion problems for now */
{
- int errcode = 0;
- int unit, part;
- struct disk_parms disk_parms;
- struct sd_data *sd ;
+ errval errcode = 0;
+ u_int32 unit, part;
+ struct sd_data *sd;
+ struct scsi_link *sc_link;
unit = UNIT(dev);
part = PARTITION(dev);
sd = sd_data[unit];
-#ifdef SDDEBUG
- if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
- printf("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n"
- , dev, unit, NSD, part);
-#endif /*SDDEBUG*/
- /*******************************************************\
- * Check the unit is legal *
- \*******************************************************/
- if ( unit >= NSD )
- {
- return(ENXIO);
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= NSD) {
+ return (ENXIO);
}
- /*******************************************************\
- * Make sure the disk has been initialised *
- * At some point in the future, get the scsi driver *
- * to look for a new device if we are not initted *
- \*******************************************************/
- if (! (sd->flags & SDINIT))
- {
- return(ENXIO);
+ /*
+ * Make sure the disk has been initialised
+ * At some point in the future, get the scsi driver
+ * to look for a new device if we are not initted
+ */
+ if ((!sd) || (!(sd->flags & SDINIT))) {
+ return (ENXIO);
}
+ sc_link = sd->sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1,
+ ("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n"
+ ,dev, unit, NSD, part));
+
+ /*
+ * "unit attention" errors should occur here if the
+ * drive has been restarted or the pack changed.
+ * just ingnore the result, it's a decoy instruction
+ * The error code will act on the error though
+ * and invalidate any media information we had.
+ */
+ scsi_test_unit_ready(sc_link, 0);
+
+ /*
+ * If it's been invalidated, then forget the label
+ */
+ sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ sd->flags &= ~SDHAVELABEL;
- /*******************************************************\
- * If it's been invalidated, and not everybody has *
- * closed it then forbid re-entry. *
- \*******************************************************/
- if ((! (sd->flags & SDVALID))
- && ( sd->openparts))
- return(ENXIO);
- /*******************************************************\
- * "unit attention" errors should occur here if the *
- * drive has been restarted or the pack changed. *
- * just ingnore the result, it's a decoy instruction *
- * The error code will act on the error though *
- * and invalidate any media information we had. *
- \*******************************************************/
- sd_test_unit_ready(unit,0);
-
- /*******************************************************\
- * In case it is a funny one, tell it to start *
- * not needed for most hard drives (ignore failure) *
- \*******************************************************/
- sd_start_unit(unit,SCSI_ERR_OK|SCSI_SILENT);
-
- /*******************************************************\
- * Check that it is still responding and ok. *
- \*******************************************************/
- if (sd_test_unit_ready(unit,0))
- {
-#ifdef SDDEBUG
- if(scsi_debug & TRACEOPENS) printf("device not reponding\n");
-#endif /*SDDEBUG*/
- return(ENXIO);
+ /*
+ * If somebody still has it open, then forbid re-entry.
+ */
+ if (sd->openparts) {
+ errcode = ENXIO;
+ goto bad;
+ }
+ }
+ /*
+ * In case it is a funny one, tell it to start
+ * not needed for most hard drives (ignore failure)
+ */
+ scsi_start_unit(sc_link, SCSI_ERR_OK | SCSI_SILENT);
+
+ /*
+ * Check that it is still responding and ok.
+ */
+ if (scsi_test_unit_ready(sc_link, 0)) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("device not reponding\n"));
+ errcode = ENXIO;
+ goto bad;
}
-#ifdef SDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("device ok\n");
-#endif /*SDDEBUG*/
-
- /*******************************************************\
- * Load the physical device parameters *
- \*******************************************************/
- sd_get_parms(unit, 0); /* sets SDVALID */
- if (sd->params.secsiz != SECSIZE) /* XXX One day...*/
- {
- printf("sd%d: Can't deal with %d bytes logical blocks\n"
- ,unit, sd->params.secsiz);
+ SC_DEBUG(sc_link, SDEV_DB3, ("device ok\n"));
+
+ /*
+ * Load the physical device parameters
+ */
+ sd_get_parms(unit, 0); /* sets SDEV_MEDIA_LOADED */
+ if (sd->params.secsiz != SECSIZE) { /* XXX One day... */
+ printf("sd%d: Can't deal with %d bytes logical blocks\n",
+ unit, sd->params.secsiz);
Debugger();
- return(ENXIO);
+ errcode = ENXIO;
+ goto bad;
}
-#ifdef SDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("Params loaded ");
-#endif /*SDDEBUG*/
- /*******************************************************\
- * Load the partition info if not already loaded *
- * Lock the pack in *
- \*******************************************************/
- sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT);
- if((errcode = sdgetdisklabel(unit)) && (part != RAW_PART))
- {
- sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT);
- return(errcode);
+ SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded "));
+
+ /* Lock the pack in. */
+ scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT);
+
+ /*
+ * Load the partition info if not already loaded.
+ */
+ if ((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) {
+ goto bad;
}
-#ifdef SDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("Disklabel loaded ");
-#endif /*SDDEBUG*/
- /*******************************************************\
- * Check the partition is legal *
- \*******************************************************/
- if ( part >= MAXPARTITIONS ) {
- sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
- return(ENXIO);
+ SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel loaded "));
+ /*
+ * Check the partition is legal
+ */
+ if (part >= MAXPARTITIONS) {
+ errcode = ENXIO;
+ goto bad;
}
-#ifdef SDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("ok");
-#endif /*SDDEBUG*/
- /*******************************************************\
- * Check that the partition exists *
- \*******************************************************/
- if (( sd->disklabel.d_partitions[part].p_size == 0 )
- && (part != RAW_PART))
- {
- sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
- return(ENXIO);
+ SC_DEBUG(sc_link, SDEV_DB3, ("partition ok"));
+
+ /*
+ * Check that the partition exists
+ */
+ if ((sd->disklabel.d_partitions[part].p_size == 0)
+ && (part != RAW_PART)) {
+ errcode = ENXIO;
+ goto bad;
}
sd->partflags[part] |= SDOPEN;
sd->openparts |= (1 << part);
-#ifdef SDDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("open %d %d\n",sdstrats,sdqueues);
-#endif /*SDDEBUG*/
- return(0);
-}
+ SC_DEBUG(sc_link, SDEV_DB3, ("open %d %d\n", sdstrats, sdqueues));
+ return 0;
-/*******************************************************\
-* Get ownership of a scsi_xfer *
-* If need be, sleep on it, until it comes free *
-\*******************************************************/
-struct scsi_xfer *sd_get_xs(unit,flags)
-int flags;
-int unit;
-{
- struct scsi_xfer *xs;
- int s;
-
- if(flags & (SCSI_NOSLEEP | SCSI_NOMASK))
- {
- if (xs = sd_free_xfer[unit])
- {
- sd_free_xfer[unit] = xs->next;
- xs->flags = 0;
- }
- }
- else
- {
- s = SPLSD();
- while (!(xs = sd_free_xfer[unit]))
- {
- sd_xfer_block_wait[unit]++; /* someone waiting! */
- sleep((caddr_t)&sd_free_xfer[unit], PRIBIO+1);
- sd_xfer_block_wait[unit]--;
- }
- sd_free_xfer[unit] = xs->next;
- splx(s);
- xs->flags = 0;
+bad:
+ if (!(sd->openparts)) {
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT);
+ sc_link->flags &= ~SDEV_OPEN;
}
- return(xs);
+ return errcode;
}
-/*******************************************************\
-* Free a scsi_xfer, wake processes waiting for it *
-\*******************************************************/
-sd_free_xs(unit,xs,flags)
-struct scsi_xfer *xs;
-int unit;
-int flags;
+/*
+ * close the device.. only called if we are the LAST occurence of an open
+ * device. Convenient now but usually a pain.
+ */
+errval
+sdclose(dev)
+ dev_t dev;
{
- int s;
-
- if(flags & SCSI_NOMASK)
- {
- if (sd_xfer_block_wait[unit])
- {
- printf("doing a wakeup from NOMASK mode\n");
- wakeup((caddr_t)&sd_free_xfer[unit]);
- }
- xs->next = sd_free_xfer[unit];
- sd_free_xfer[unit] = xs;
- }
- else
- {
- s = SPLSD();
- if (sd_xfer_block_wait[unit])
- wakeup((caddr_t)&sd_free_xfer[unit]);
- xs->next = sd_free_xfer[unit];
- sd_free_xfer[unit] = xs;
- splx(s);
- }
+ unsigned char unit, part;
+ struct sd_data *sd;
+
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ sd = sd_data[unit];
+ sd->partflags[part] &= ~SDOPEN;
+ sd->openparts &= ~(1 << part);
+ scsi_prevent(sd->sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK);
+ if (!(sd->openparts))
+ sd->sc_link->flags &= ~SDEV_OPEN;
+ return 0;
}
-/*******************************************************\
-* trim the size of the transfer if needed, *
-* called by physio *
-* basically the smaller of our max and the scsi driver's*
-* minphys (note we have no max) *
-\*******************************************************/
-/* Trim buffer length if buffer-size is bigger than page size */
-void sdminphys(bp)
-struct buf *bp;
+/*
+ * trim the size of the transfer if needed, called by physio
+ * basically the smaller of our max and the scsi driver's
+ * minphys (note we have no max)
+ *
+ * Trim buffer length if buffer-size is bigger than page size
+ */
+void
+sdminphys(bp)
+ struct buf *bp;
{
- (*(sd_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp);
+ (*(sd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
}
-/*******************************************************\
-* Actually translate the requested transfer into *
-* one the physical driver can understand *
-* The transfer is described by a buf and will include *
-* only one physical transfer. *
-\*******************************************************/
-
-int sdstrategy(bp)
-struct buf *bp;
+/*
+ * Actually translate the requested transfer into one the physical driver
+ * can understand. The transfer is described by a buf and will include
+ * only one physical transfer.
+ */
+errval
+sdstrategy(bp)
+ struct buf *bp;
{
- struct buf *dp;
- unsigned int opri;
- struct sd_data *sd ;
- int unit;
+ struct buf *dp;
+ u_int32 opri;
+ struct sd_data *sd;
+ u_int32 unit;
sdstrats++;
unit = UNIT((bp->b_dev));
sd = sd_data[unit];
-#ifdef SDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("\nsdstrategy ");
- if(scsi_debug & SHOWREQUESTS) printf("sd%d: %d bytes @ blk%d\n",
- unit,bp->b_bcount,bp->b_blkno);
-#endif /*SDDEBUG*/
+ SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy "));
+ SC_DEBUG(sd->sc_link, SDEV_DB1,
+ (" %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno));
sdminphys(bp);
- /*******************************************************\
- * If the device has been made invalid, error out *
- \*******************************************************/
- if(!(sd->flags & SDVALID))
- {
+ /*
+ * If the device has been made invalid, error out
+ */
+ if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED)) {
+ sd->flags &= ~SDHAVELABEL;
bp->b_error = EIO;
goto bad;
}
- /*******************************************************\
- * "soft" write protect check *
- \*******************************************************/
+ /*
+ * "soft" write protect check
+ */
if ((sd->flags & SDWRITEPROT) && (bp->b_flags & B_READ) == 0) {
bp->b_error = EROFS;
goto bad;
}
- /*******************************************************\
- * If it's a null transfer, return immediatly *
- \*******************************************************/
- if (bp->b_bcount == 0)
- {
+ /*
+ * If it's a null transfer, return immediatly
+ */
+ if (bp->b_bcount == 0) {
goto done;
}
-
- /*******************************************************\
- * Decide which unit and partition we are talking about *
- * only raw is ok if no label *
- \*******************************************************/
- if(PARTITION(bp->b_dev) != RAW_PART)
- {
- if (!(sd->flags & SDHAVELABEL))
- {
+ /*
+ * Decide which unit and partition we are talking about
+ * only raw is ok if no label
+ */
+ if (PARTITION(bp->b_dev) != RAW_PART) {
+ if (!(sd->flags & SDHAVELABEL)) {
bp->b_error = EIO;
goto bad;
}
-
/*
* do bounds checking, adjust transfer. if error, process.
* if end of partition, just return
*/
- if (bounds_check_with_label(bp,&sd->disklabel,sd->wlabel) <= 0)
+ if (bounds_check_with_label(bp, &sd->disklabel, sd->wlabel) <= 0)
goto done;
/* otherwise, process transfer request */
}
-
opri = SPLSD();
- dp = &sd_buf_queue[unit];
+ dp = &sd->buf_queue;
- /*******************************************************\
- * Place it in the queue of disk activities for this disk*
- \*******************************************************/
+ /*
+ * Place it in the queue of disk activities for this disk
+ */
disksort(dp, bp);
- /*******************************************************\
- * Tell the device to get going on the transfer if it's *
- * not doing anything, otherwise just wait for completion*
- \*******************************************************/
+ /*
+ * Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion
+ */
sdstart(unit);
splx(opri);
- return;
+ return 0;
bad:
bp->b_flags |= B_ERROR;
done:
- /*******************************************************\
- * Correctly set the buf to indicate a completed xfer *
- \*******************************************************/
- bp->b_resid = bp->b_bcount;
+ /*
+ * Correctly set the buf to indicate a completed xfer
+ */
+ bp->b_resid = bp->b_bcount;
biodone(bp);
- return;
+ return 0;
}
-/***************************************************************\
-* sdstart looks to see if there is a buf waiting for the device *
-* and that the device is not already busy. If both are true, *
-* It dequeues the buf and creates a scsi command to perform the *
-* transfer in the buf. The transfer request will call sd_done *
-* on completion, which will in turn call this routine again *
-* so that the next queued transfer is performed. *
-* The bufs are queued by the strategy routine (sdstrategy) *
-* *
-* This routine is also called after other non-queued requests *
-* have been made of the scsi driver, to ensure that the queue *
-* continues to be drained. *
-* *
-* must be called at the correct (highish) spl level *
-\***************************************************************/
-/* sdstart() is called at SPLSD from sdstrategy and sd_done*/
+/*
+ * sdstart looks to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It dequeues the buf and creates a scsi command to perform the
+ * transfer in the buf. The transfer request will call scsi_done
+ * on completion, which will in turn call this routine again
+ * so that the next queued transfer is performed.
+ * The bufs are queued by the strategy routine (sdstrategy)
+ *
+ * This routine is also called after other non-queued requests
+ * have been made of the scsi driver, to ensure that the queue
+ * continues to be drained.
+ *
+ * must be called at the correct (highish) spl level
+ * sdstart() is called at SPLSD from sdstrategy and scsi_done
+ */
+void
sdstart(unit)
-int unit;
+ u_int32 unit;
{
- int drivecount;
- register struct buf *bp = 0;
- register struct buf *dp;
- struct scsi_xfer *xs;
- struct scsi_rw_big cmd;
- int blkno, nblk;
- struct sd_data *sd = sd_data[unit];
- struct partition *p ;
-
-#ifdef SDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("sdstart%d ",unit);
-#endif /*SDDEBUG*/
- /*******************************************************\
- * Check if the device is already running full capacity *
- \*******************************************************/
- if(!sd_free_xfer[unit])
- {
- return; /* none for us, unit already underway */
- }
-
- /*******************************************************\
- * there is excess capacity, but a special waits *
- * It'll need the adapter as soon as we clear out of the *
- * way and let it run (user level wait). *
- \*******************************************************/
- if(sd_xfer_block_wait[unit])
- {
- return;
- }
+ register struct sd_data *sd = sd_data[unit];
+ register struct scsi_link *sc_link = sd->sc_link;
+ struct buf *bp = 0;
+ struct buf *dp;
+ struct scsi_rw_big cmd;
+ u_int32 blkno, nblk;
+ struct partition *p;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("sdstart "));
+ /*
+ * Check if the device has room for another command
+ */
+ while (sc_link->opennings) {
- /*******************************************************\
- * See if there is a buf with work for us to do.. *
- \*******************************************************/
- dp = &sd_buf_queue[unit];
- if ((bp = dp->b_actf) == NULL) /* yes, an assign */
- {
- return;
- }
+ /*
+ * there is excess capacity, but a special waits
+ * It'll need the adapter as soon as we clear out of the
+ * way and let it run (user level wait).
+ */
+ if (sc_link->flags & SDEV_WAITING) {
+ return;
+ }
+ /*
+ * See if there is a buf with work for us to do..
+ */
+ dp = &sd->buf_queue;
+ if ((bp = dp->b_actf) == NULL) { /* yes, an assign */
+ return;
+ }
+ dp->b_actf = bp->av_forw;
- dp->b_actf = bp->av_forw;
+ /*
+ * If the device has become invalid, abort all the
+ * reads and writes until all files have been closed and
+ * re-openned
+ */
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ sd->flags &= ~SDHAVELABEL;
+ goto bad;
+ }
+ /*
+ * We have a buf, now we know we are going to go through
+ * With this thing..
+ *
+ * First, translate the block to absolute
+ */
+ p = sd->disklabel.d_partitions + PARTITION(bp->b_dev);
+ blkno = bp->b_blkno + p->p_offset;
+ nblk = (bp->b_bcount + 511) >> 9;
- /*******************************************************\
- * If the device has become invalid, abort all the *
- * reads and writes until all files have been closed and *
- * re-openned *
- \*******************************************************/
- if(!(sd->flags & SDVALID))
- {
- goto bad;
- }
- /*******************************************************\
- * We have a buf, now we know we are going to go through *
- * With this thing.. *
- * *
- * First, translate the block to absolute *
- \*******************************************************/
- p = sd->disklabel.d_partitions + PARTITION(bp->b_dev);
- blkno = bp->b_blkno + p->p_offset;
- nblk = (bp->b_bcount + 511) >> 9;
-
- /*******************************************************\
- * Fill out the scsi command *
- \*******************************************************/
- bzero(&cmd, sizeof(cmd));
- cmd.op_code = (bp->b_flags & B_READ)
- ? READ_BIG : WRITE_BIG;
- cmd.addr_3 = (blkno & 0xff000000) >> 24;
- cmd.addr_2 = (blkno & 0xff0000) >> 16;
- cmd.addr_1 = (blkno & 0xff00) >> 8;
- cmd.addr_0 = blkno & 0xff;
- cmd.length2 = (nblk & 0xff00) >> 8;
- cmd.length1 = (nblk & 0xff);
- /*******************************************************\
- * Call the routine that chats with the adapter *
- * Note: we cannot sleep as we may be an interrupt *
- \*******************************************************/
- if (sd_scsi_cmd(unit,
- &cmd,
+ /*
+ * Fill out the scsi command
+ */
+ bzero(&cmd, sizeof(cmd));
+ cmd.op_code = (bp->b_flags & B_READ)
+ ? READ_BIG : WRITE_BIG;
+ cmd.addr_3 = (blkno & 0xff000000) >> 24;
+ cmd.addr_2 = (blkno & 0xff0000) >> 16;
+ cmd.addr_1 = (blkno & 0xff00) >> 8;
+ cmd.addr_0 = blkno & 0xff;
+ cmd.length2 = (nblk & 0xff00) >> 8;
+ cmd.length1 = (nblk & 0xff);
+ /*
+ * Call the routine that chats with the adapter.
+ * Note: we cannot sleep as we may be an interrupt
+ */
+ if (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &cmd,
sizeof(cmd),
- (u_char *)bp->b_un.b_addr,
+ (u_char *) bp->b_un.b_addr,
bp->b_bcount,
+ SD_RETRIES,
10000,
bp,
- SCSI_NOSLEEP| ((bp->b_flags & B_READ)?
- SCSI_DATA_IN : SCSI_DATA_OUT))
- != SUCCESSFULLY_QUEUED)
- {
+ SCSI_NOSLEEP | ((bp->b_flags & B_READ) ?
+ SCSI_DATA_IN : SCSI_DATA_OUT))
+ == SUCCESSFULLY_QUEUED) {
+ sdqueues++;
+ } else {
bad:
- printf("sd%d: oops not queued",unit);
- bp->b_error = EIO;
- bp->b_flags |= B_ERROR;
- biodone(bp);
- return ;
+ printf("sd%d: oops not queued", unit);
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ }
}
- sdqueues++;
}
-/*******************************************************\
-* Perform special action on behalf of the user *
-* Knows about the internals of this device *
-\*******************************************************/
+/*
+ * Perform special action on behalf of the user
+ * Knows about the internals of this device
+ */
+errval
sdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
{
- /* struct sd_cmd_buf *args;*/
- int error = 0;
- unsigned int opri;
+ /* struct sd_cmd_buf *args; */
+ errval error = 0;
unsigned char unit, part;
register struct sd_data *sd;
-
- /*******************************************************\
- * Find the device that the user is talking about *
- \*******************************************************/
+ /*
+ * Find the device that the user is talking about
+ */
unit = UNIT(dev);
part = PARTITION(dev);
sd = sd_data[unit];
-#ifdef SDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("sdioctl%d ",unit);
-#endif /*SDDEBUG*/
-
- /*******************************************************\
- * If the device is not valid.. abandon ship *
- \*******************************************************/
- if (!(sd->flags & SDVALID))
- return(EIO);
- switch(cmd)
- {
+ SC_DEBUG(sd->sc_link, SDEV_DB1, ("sdioctl (0x%x)", cmd));
+
+ /*
+ * If the device is not valid.. abandon ship
+ */
+ if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED))
+ return (EIO);
+ switch (cmd) {
case DIOCSBAD:
- error = EINVAL;
+ error = EINVAL;
break;
case DIOCGDINFO:
- *(struct disklabel *)addr = sd->disklabel;
+ *(struct disklabel *) addr = sd->disklabel;
+ break;
+
+ case DIOCGPART:
+ ((struct partinfo *) addr)->disklab = &sd->disklabel;
+ ((struct partinfo *) addr)->part =
+ &sd->disklabel.d_partitions[PARTITION(dev)];
break;
- case DIOCGPART:
- ((struct partinfo *)addr)->disklab = &sd->disklabel;
- ((struct partinfo *)addr)->part =
- &sd->disklabel.d_partitions[PARTITION(dev)];
- break;
-
- case DIOCSDINFO:
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else
- error = setdisklabel(&sd->disklabel,
- (struct disklabel *)addr,
- /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */0,
- sd->dosparts);
- if (error == 0) {
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ error = setdisklabel(&sd->disklabel,
+ (struct disklabel *)addr,
+ /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */ 0,
+#ifdef NetBSD
+ &sd->cpudisklabel
+#else
+ sd->dosparts
+#endif
+ );
+ if (error == 0) {
sd->flags |= SDHAVELABEL;
}
- break;
+ break;
- case DIOCWLABEL:
+ case DIOCWLABEL:
sd->flags &= ~SDWRITEPROT;
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else
- sd->wlabel = *(int *)addr;
- break;
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ sd->wlabel = *(boolean *) addr;
+ break;
- case DIOCWDINFO:
+ case DIOCWDINFO:
sd->flags &= ~SDWRITEPROT;
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else
- {
- if ((error = setdisklabel(&sd->disklabel
- , (struct disklabel *)addr
- , /*(sd->flags & SDHAVELABEL) ? sd->openparts :*/ 0
- , sd->dosparts)) == 0)
- {
- int wlab;
-
- sd->flags |= SDHAVELABEL; /* ok write will succeed */
-
- /* simulate opening partition 0 so write succeeds */
- sd->openparts |= (1 << 0); /* XXX */
- wlab = sd->wlabel;
- sd->wlabel = 1;
- error = writedisklabel(dev, sdstrategy,
- &sd->disklabel, sd->dosparts);
- sd->wlabel = wlab;
- }
- }
- break;
-
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else {
+ error = setdisklabel(&sd->disklabel,
+ (struct disklabel *)addr,
+ /*(sd->flags & SDHAVELABEL) ? sd->openparts : */ 0,
+#ifdef NetBSD
+ &sd->cpudisklabel
+#else
+ sd->dosparts
+#endif
+ );
+ if (!error) {
+ boolean wlab;
+
+ /* ok - write will succeed */
+ sd->flags |= SDHAVELABEL;
+
+ /* simulate opening partition 0 so write succeeds */
+ sd->openparts |= (1 << 0); /* XXX */
+ wlab = sd->wlabel;
+ sd->wlabel = 1;
+ error = writedisklabel(dev, sdstrategy,
+ &sd->disklabel,
+#ifdef NetBSD
+ &sd->cpudisklabel
+#else
+ sd->dosparts
+#endif
+ );
+ sd->wlabel = wlab;
+ }
+ }
+ break;
default:
- error = ENOTTY;
+ if (part == RAW_PART)
+ error = scsi_do_ioctl(sd->sc_link, cmd, addr, flag);
+ else
+ error = ENOTTY;
break;
}
- return (error);
+ return error;
}
-
-/*******************************************************\
-* Load the label information on the named device *
-\*******************************************************/
-int sdgetdisklabel(unit)
-unsigned char unit;
+/*
+ * Load the label information on the named device
+ */
+errval
+sdgetdisklabel(unsigned char unit)
{
- /*unsigned int n, m;*/
- char *errstring;
- struct dos_partition *dos_partition_p;
+ char *errstring;
struct sd_data *sd = sd_data[unit];
- /*******************************************************\
- * If the inflo is already loaded, use it *
- \*******************************************************/
- if(sd->flags & SDHAVELABEL) return(ESUCCESS);
-
- bzero(&sd->disklabel,sizeof(struct disklabel));
- /*******************************************************\
- * make partition 3 the whole disk in case of failure *
- * then get pdinfo *
- * for historical reasons, make part a same as raw part *
- \*******************************************************/
+ /*
+ * If the inflo is already loaded, use it
+ */
+ if (sd->flags & SDHAVELABEL)
+ return (ESUCCESS);
+
+ bzero(&sd->disklabel, sizeof(struct disklabel));
+ /*
+ * make partition 3 the whole disk in case of failure then get pdinfo
+ * for historical reasons, make part a same as raw part
+ */
sd->disklabel.d_partitions[0].p_offset = 0;
sd->disklabel.d_partitions[0].p_size = sd->params.disksize;
sd->disklabel.d_partitions[RAW_PART].p_offset = 0;
sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize;
sd->disklabel.d_npartitions = MAXPARTITIONS;
- sd->disklabel.d_secsize = 512; /* as long as it's not 0 */
+ sd->disklabel.d_secsize = SECSIZE; /* as long as it's not 0 */
sd->disklabel.d_ntracks = sd->params.heads;
sd->disklabel.d_nsectors = sd->params.sectors;
sd->disklabel.d_ncylinders = sd->params.cyls;
sd->disklabel.d_secpercyl = sd->params.heads * sd->params.sectors;
- if (sd->disklabel.d_secpercyl == 0)
- {
+ if (sd->disklabel.d_secpercyl == 0) {
sd->disklabel.d_secpercyl = 100;
- /* as long as it's not 0 */
- /* readdisklabel divides by it (?)*/
+ /* as long as it's not 0 - readdisklabel divides by it (?) */
}
-
- /*******************************************************\
- * Call the generic disklabel extraction routine *
- \*******************************************************/
- if(errstring = readdisklabel(makedev(0 ,(unit<<UNITSHIFT )+3)
- , sdstrategy
- , &sd->disklabel
- , sd->dosparts
- , 0
- , 0))
- {
- printf("sd%d: %s\n",unit, errstring);
- return(ENXIO);
+ /*
+ * Call the generic disklabel extraction routine
+ */
+ if (errstring = readdisklabel(makedev(0, (unit << UNITSHIFT) + 3),
+ sdstrategy,
+ &sd->disklabel,
+#ifdef NetBSD
+ &sd->cpudisklabel
+#else
+ sd->dosparts,
+ 0,
+ 0
+#endif
+ )) {
+ printf("sd%d: %s\n", unit, errstring);
+ return ENXIO;
}
-
- sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */
- return(ESUCCESS);
+ sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */
+ return ESUCCESS;
}
-/*******************************************************\
-* Find out from the device what it's capacity is *
-\*******************************************************/
+/*
+ * Find out from the device what it's capacity is
+ */
+u_int32
sd_size(unit, flags)
+ int unit, flags;
{
struct scsi_read_cap_data rdcap;
struct scsi_read_capacity scsi_cmd;
- int size;
+ u_int32 size;
- /*******************************************************\
- * make up a scsi command and ask the scsi driver to do *
- * it for you. *
- \*******************************************************/
+ /*
+ * make up a scsi command and ask the scsi driver to do
+ * it for you.
+ */
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = READ_CAPACITY;
- /*******************************************************\
- * If the command works, interpret the result as a 4 byte*
- * number of blocks *
- \*******************************************************/
- if (sd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- &rdcap,
- sizeof(rdcap),
- 6000,
- NULL,
- flags | SCSI_DATA_IN) != 0)
- {
+ /*
+ * If the command works, interpret the result as a 4 byte
+ * number of blocks
+ */
+ if (scsi_scsi_cmd(sd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & rdcap,
+ sizeof(rdcap),
+ SD_RETRIES,
+ 2000,
+ NULL,
+ flags | SCSI_DATA_IN) != 0) {
printf("sd%d: could not get size\n", unit);
- return(0);
+ return (0);
} else {
- size = rdcap.addr_0 + 1 ;
+ size = rdcap.addr_0 + 1;
size += rdcap.addr_1 << 8;
size += rdcap.addr_2 << 16;
size += rdcap.addr_3 << 24;
}
- return(size);
-}
-
-/*******************************************************\
-* Get scsi driver to send a "are you ready?" command *
-\*******************************************************/
-sd_test_unit_ready(unit,flags)
-int unit,flags;
-{
- struct scsi_test_unit_ready scsi_cmd;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = TEST_UNIT_READY;
-
- return (sd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 100000,
- NULL,
- flags));
-}
-
-/*******************************************************\
-* Prevent or allow the user to remove the tape *
-* Don't change this status if any partitions are open *
-\*******************************************************/
-sd_prevent(unit,type,flags)
-int unit,type,flags;
-{
- struct scsi_prevent scsi_cmd;
-
- if(sd_data[unit]->openparts) return;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = PREVENT_ALLOW;
- scsi_cmd.how=type;
- return (sd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 5000,
- NULL,
- flags) );
-}
-/*******************************************************\
-* Get scsi driver to send a "start up" command *
-\*******************************************************/
-sd_start_unit(unit,flags)
-int unit,flags;
-{
- struct scsi_start_stop scsi_cmd;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = START_STOP;
- scsi_cmd.how = SSS_START;
-
- return (sd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 6000,
- NULL,
- flags));
+ return (size);
}
-/*******************************************************\
-* Tell the device to map out a defective block *
-\*******************************************************/
-sd_reassign_blocks(unit,block)
+/*
+ * Tell the device to map out a defective block
+ */
+errval
+sd_reassign_blocks(unit, block)
+ int unit, block;
{
- struct scsi_reassign_blocks scsi_cmd;
- struct scsi_reassign_blocks_data rbdata;
-
+ struct scsi_reassign_blocks scsi_cmd;
+ struct scsi_reassign_blocks_data rbdata;
bzero(&scsi_cmd, sizeof(scsi_cmd));
bzero(&rbdata, sizeof(rbdata));
@@ -905,108 +777,67 @@ sd_reassign_blocks(unit,block)
rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]);
rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff);
rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff);
- rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff);
- rbdata.defect_descriptor[0].dlbaddr_0 = ((block ) & 0xff);
-
- return(sd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- &rbdata,
- sizeof(rbdata),
- 5000,
- NULL,
- SCSI_DATA_OUT));
+ rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff);
+ rbdata.defect_descriptor[0].dlbaddr_0 = ((block) & 0xff);
+
+ return (scsi_scsi_cmd(sd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & rbdata,
+ sizeof(rbdata),
+ SD_RETRIES,
+ 5000,
+ NULL,
+ SCSI_DATA_OUT));
}
-
#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
-/*******************************************************\
-* Get the scsi driver to send a full inquiry to the *
-* device and use the results to fill out the disk *
-* parameter structure. *
-\*******************************************************/
-
-int sd_get_parms(unit, flags)
+/*
+ * Get the scsi driver to send a full inquiry to the
+ * device and use the results to fill out the disk
+ * parameter structure.
+ */
+errval
+sd_get_parms(unit, flags)
+ int unit, flags;
{
struct sd_data *sd = sd_data[unit];
struct disk_parms *disk_parms = &sd->params;
- struct scsi_mode_sense scsi_cmd;
- struct scsi_mode_sense_data
- {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- union disk_pages pages;
- }scsi_sense;
- int sectors;
-
- /*******************************************************\
- * First check if we have it all loaded *
- \*******************************************************/
- if(sd->flags & SDVALID) return(0);
- /*******************************************************\
- * First do a mode sense page 3 *
- \*******************************************************/
-#ifdef SDDEBUG
- if (sd_debug)
- {
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = MODE_SENSE;
- scsi_cmd.page = 3;
- scsi_cmd.length = 0x24;
- /*******************************************************\
- * do the command, but we don't need the results *
- * just print them for our interest's sake *
- \*******************************************************/
- if (sd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- &scsi_sense,
- sizeof(scsi_sense),
- 2000,
- NULL,
- flags | SCSI_DATA_IN) != 0)
- {
- printf("sd%d: could not mode sense (3)\n", unit);
- }
- else
- {
- printf("unit %d: %d trk/zone, %d alt_sec/zone, %d alt_trk/zone, %d alt_trk/lun\n",
- unit,
- b2tol(scsi_sense.pages.disk_format.trk_z),
- b2tol(scsi_sense.pages.disk_format.alt_sec),
- b2tol(scsi_sense.pages.disk_format.alt_trk_z),
- b2tol(scsi_sense.pages.disk_format.alt_trk_v));
- printf(" %d sec/trk, %d bytes/sec, %d interleave, %d %d bytes/log_blk\n",
- b2tol(scsi_sense.pages.disk_format.ph_sec_t),
- b2tol(scsi_sense.pages.disk_format.bytes_s),
- b2tol(scsi_sense.pages.disk_format.interleave),
- sd_size(unit, flags),
- _3btol(scsi_sense.blk_desc.blklen));
- }
- }
-#endif /*SDDEBUG*/
-
-
- /*******************************************************\
- * do a "mode sense page 4" *
- \*******************************************************/
+ struct scsi_mode_sense scsi_cmd;
+ struct scsi_mode_sense_data {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ union disk_pages pages;
+ } scsi_sense;
+ u_int32 sectors;
+
+ /*
+ * First check if we have it all loaded
+ */
+ if (sd->flags & SDEV_MEDIA_LOADED)
+ return 0;
+
+ /*
+ * do a "mode sense page 4"
+ */
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = MODE_SENSE;
scsi_cmd.page = 4;
scsi_cmd.length = 0x20;
- /*******************************************************\
- * If the command worked, use the results to fill out *
- * the parameter structure *
- \*******************************************************/
- if (sd_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- &scsi_sense,
- sizeof(scsi_sense),
- 2000,
- NULL,
- flags | SCSI_DATA_IN) != 0)
- {
+ /*
+ * If the command worked, use the results to fill out
+ * the parameter structure
+ */
+ if (scsi_scsi_cmd(sd->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & scsi_sense,
+ sizeof(scsi_sense),
+ SD_RETRIES,
+ 2000,
+ NULL,
+ flags | SCSI_DATA_IN) != 0) {
+
printf("sd%d could not mode sense (4).", unit);
printf(" Using ficticious geometry\n");
/*
@@ -1017,631 +848,212 @@ int sd_get_parms(unit, flags)
sectors = sd_size(unit, flags);
disk_parms->heads = 64;
disk_parms->sectors = 32;
- disk_parms->cyls = sectors/(64 * 32);
+ disk_parms->cyls = sectors / (64 * 32);
disk_parms->secsiz = SECSIZE;
disk_parms->disksize = sectors;
- }
- else
- {
+ } else {
-#ifdef SDDEBUG
- if (sd_debug)
- {
- printf(" %d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n",
+ SC_DEBUG(sd->sc_link, SDEV_DB3,
+ ("%d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n",
_3btol(&scsi_sense.pages.rigid_geometry.ncyl_2),
scsi_sense.pages.rigid_geometry.nheads,
b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp),
b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc),
- b2tol(scsi_sense.pages.rigid_geometry.land_zone));
- }
-#endif /*SDDEBUG*/
-
- /*******************************************************\
- * KLUDGE!!(for zone recorded disks) *
- * give a number of sectors so that sec * trks * cyls *
- * is <= disk_size *
- * can lead to wasted space! THINK ABOUT THIS ! *
- \*******************************************************/
+ b2tol(scsi_sense.pages.rigid_geometry.land_zone)));
+
+ /*
+ * KLUDGE!!(for zone recorded disks)
+ * give a number of sectors so that sec * trks * cyls
+ * is <= disk_size
+ * can lead to wasted space! THINK ABOUT THIS !
+ */
disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads;
disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2);
- disk_parms->secsiz = _3btol(&scsi_sense.blk_desc.blklen);
+ disk_parms->secsiz = _3btol(scsi_sense.blk_desc.blklen);
sectors = sd_size(unit, flags);
disk_parms->disksize = sectors;
sectors /= (disk_parms->heads * disk_parms->cyls);
- disk_parms->sectors = sectors; /* dubious on SCSI*//*XXX*/
+ disk_parms->sectors = sectors; /* dubious on SCSI *//*XXX */
}
-
- sd->flags |= SDVALID;
- return(0);
+ sd->sc_link->flags |= SDEV_MEDIA_LOADED;
+ return 0;
}
-/*******************************************************\
-* close the device.. only called if we are the LAST *
-* occurence of an open device *
-* convenient now but usually a pain *
-\*******************************************************/
-sdclose(dev)
-dev_t dev;
+int
+sdsize(dev_t dev)
{
- unsigned char unit, part;
- unsigned int old_priority;
+ u_int32 unit = UNIT(dev), part = PARTITION(dev), val;
struct sd_data *sd;
- unit = UNIT(dev);
- part = PARTITION(dev);
- sd = sd_data[unit];
- sd->partflags[part] &= ~SDOPEN;
- sd->openparts &= ~(1 << part);
- sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK);
- return(0);
-}
-
-/*******************************************************\
-* This routine is called by the scsi interrupt when *
-* the transfer is complete.
-\*******************************************************/
-int sd_done(unit,xs)
-int unit;
-struct scsi_xfer *xs;
-{
- struct buf *bp;
- int retval;
- int retries = 0;
-
-#ifdef SDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit);
-#endif /*SDDEBUG*/
-#ifdef PARANOID
- if (! (xs->flags & INUSE))
- panic("scsi_xfer not in use!");
-#endif
- if((bp = xs->bp) == NULL)
- {
- /***********************************************\
- * if it's a normal user level request, then ask *
- * The user level code to handle error checking *
- * rather than doing it here at interrupt time *
- \***********************************************/
- wakeup(xs);
- return;
- }
-
- /***********************************************\
- * If it has a buf, we might be working with *
- * a request from the buffer cache or some other *
- * piece of code that requires us to process *
- * errors right now, despite cost *
- \***********************************************/
- switch(xs->error)
- {
- case XS_NOERROR:
- bp->b_error = 0;
- bp->b_resid = 0;
- break;
-
- case XS_SENSE:
- retval = (sd_interpret_sense(unit,xs));
- if(retval)
- {
- bp->b_flags |= B_ERROR;
- bp->b_error = retval;
- }
- break;
-
- case XS_BUSY:
- /*should somehow arange for a 1 sec delay here (how?)*/
- case XS_TIMEOUT:
- /***********************************************\
- * If we can, resubmit it to the adapter. *
- \***********************************************/
- if(xs->retries--)
- {
- xs->error = XS_NOERROR;
- xs->flags &= ~ITSDONE;
- if ( (*(sd_data[unit]->sc_sw->scsi_cmd))(xs)
- == SUCCESSFULLY_QUEUED)
- { /* don't wake the job, ok? */
- return;
- }
- xs->flags |= ITSDONE;
- } /* fall through */
-
- case XS_DRIVER_STUFFUP:
- bp->b_flags |= B_ERROR;
- bp->b_error = EIO;
- break;
- default:
- printf("sd%d: unknown error category from scsi driver\n"
- ,unit);
- }
- /*******************************\
- * tell the owner we're done *
- * then free our resources *
- * and see if there's more work *
- \*******************************/
- biodone(bp);
- sd_free_xs(unit,xs,0);
- sdstart(unit); /* If there's anything waiting.. do it */
-}
-
-/*******************************************************\
-* ask the scsi driver to perform a command for us. *
-* Call it through the switch table, and tell it which *
-* sub-unit we want, and what target and lu we wish to *
-* talk to. Also tell it where to find the command *
-* and how long it is. *
-* Also tell it where to read/write the data, and how *
-* long the data is supposed to be. If we have a buf *
-* to associate with the transfer, we need that too. *
-\*******************************************************/
-int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags)
-
-int unit,flags;
-struct scsi_generic *scsi_cmd;
-int cmdlen;
-int timeout;
-u_char *data_addr;
-int datalen;
-struct buf *bp;
-{
- struct scsi_xfer *xs;
- int retval;
- int s;
- struct sd_data *sd = sd_data[unit];
-
-#ifdef SDDEBUG
- if(scsi_debug & PRINTROUTINES) printf("\nsd_scsi_cmd%d ",unit);
-#endif /*SDDEBUG*/
-
-#ifdef PARANOID
- if(!(sd->sc_sw)) /* If we have a scsi driver */
- {/* How we got here is anyone's guess */
- printf("sd%d: not set up\n",unit);
- return(EINVAL);
- }
-#endif
- xs = sd_get_xs(unit,flags); /* should wait unless booting */
-#ifdef PARANOID
- if(!xs)
- {
- printf("sd_scsi_cmd%d: controller busy"
- " (this should never happen)\n",unit);
- return(EBUSY);
- }
-#endif
- /*******************************************************\
- * Fill out the scsi_xfer structure *
- \*******************************************************/
- xs->flags = INUSE | flags;
- xs->adapter = sd->ctlr;
- xs->targ = sd->targ;
- xs->lu = sd->lu;
- xs->retries = SD_RETRIES;
- xs->timeout = timeout;
- xs->cmd = scsi_cmd;
- xs->cmdlen = cmdlen;
- xs->data = data_addr;
- xs->datalen = datalen;
- xs->resid = datalen;
- xs->when_done = sd_done;
- xs->done_arg = unit;
- xs->done_arg2 = (int)xs;
- xs->bp = bp;
-retry: xs->error = XS_NOERROR;
-
- /*******************************************************\
- * Do the transfer. If we are polling we will return: *
- * COMPLETE, Was poll, and sd_done has been called *
- * HAD_ERROR, Was poll and an error was encountered *
- * TRY_AGAIN_LATER, Adapter short resources, try again *
- * *
- * if under full steam (interrupts) it will return: *
- * SUCCESSFULLY_QUEUED, will do a wakeup when complete *
- * HAD_ERROR, had an erro before it could queue *
- * TRY_AGAIN_LATER, (as for polling) *
- * After the wakeup, we must still check if it succeeded *
- * *
- * If we have a bp however, all the error proccessing *
- * and the buffer code both expect us to return straight *
- * to them, so as soon as the command is queued, return *
- \*******************************************************/
- retval = (*(sd->sc_sw->scsi_cmd))(xs);
- if(bp) return retval; /* will sleep (or not) elsewhere */
-
- /*******************************************************\
- * Only here for non I/O cmds. It's cheaper to process *
- * the error status here than at interrupt time so *
- * sd_done will have done nothing except wake us up. *
- \*******************************************************/
- switch(retval)
- {
- case SUCCESSFULLY_QUEUED:
- s = splbio();
- while(!(xs->flags & ITSDONE))
- sleep(xs,PRIBIO+1);
- splx(s);
- /* fall through to check success of completed command */
-
- case HAD_ERROR:
- switch(xs->error)
- {
- case XS_NOERROR: /* nearly always hit this one */
- retval = ESUCCESS;
- break;
-
- case XS_SENSE:
- retval = (sd_interpret_sense(unit,xs));
- break;
- case XS_BUSY:
- /* should sleep 1 sec here */
- case XS_TIMEOUT:
- if(xs->retries-- )
- {
- xs->flags &= ~ITSDONE;
- goto retry;
- }
- case XS_DRIVER_STUFFUP:
- retval = EIO;
- break;
- default:
- retval = EIO;
- printf("sd%d: unknown error category from scsi driver\n"
- ,unit);
- }
- break;
- case COMPLETE: /* Polling command completed ok */
- retval = ESUCCESS;
- break;
+ if (unit >= NSD)
+ return -1;
- case TRY_AGAIN_LATER: /* adapter resource shortage */
- /* should sleep 1 sec here */
- if(xs->retries-- )
- {
- xs->flags &= ~ITSDONE;
- goto retry;
- }
- default:
- retval = EIO;
+ sd = sd_data[unit];
+ if (!sd)
+ return -1;
+ if ((sd->flags & SDINIT) == 0)
+ return -1;
+ if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) {
+ val = sdopen(MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0);
+ if (val != 0)
+ return -1;
}
- /*******************************************************\
- * we have finished with the xfer stuct, free it and *
- * check if anyone else needs to be started up. *
- \*******************************************************/
- sd_free_xs(unit,xs,flags);
- sdstart(unit); /* check queue */
- return(retval);
-}
-
-/***************************************************************\
-* Look at the returned sense and act on the error and detirmine *
-* The unix error number to pass back... (0 = report no error) *
-\***************************************************************/
+ if (sd->flags & SDWRITEPROT)
+ return -1;
-int sd_interpret_sense(unit,xs)
-int unit;
-struct scsi_xfer *xs;
-{
- struct scsi_sense_data *sense;
- int key;
- int silent;
- long int info;
-
- /***************************************************************\
- * If the flags say errs are ok, then always return ok. *
- \***************************************************************/
- if (xs->flags & SCSI_ERR_OK) return(ESUCCESS);
- silent = (xs->flags & SCSI_SILENT);
-
- sense = &(xs->sense);
- info = ((sense->ext.extended.info[0] <<24)|
- (sense->ext.extended.info[1] <<16)|
- (sense->ext.extended.info[2] <<8)|
- (sense->ext.extended.info[3] ));
- switch(sense->error_code & SSD_ERRCODE)
- {
- case 0x70:
- {
- key=sense->ext.extended.flags & SSD_KEY;
- switch(key)
- {
- case 0x0:
- return(ESUCCESS);
- case 0x1:
- if(!silent)
- {
- printf("sd%d: soft error(corrected) ", unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf("block no. %d (decimal)",info);
- }
- printf("\n");
- }
- return(ESUCCESS);
- case 0x2:
- if(!silent)printf("sd%d: not ready\n ",
- unit);
- return(ENODEV);
- case 0x3:
- if(!silent)
- {
- printf("sd%d: medium error ", unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf("block no. %d (decimal)",info);
- }
- printf("\n");
- }
- return(EIO);
- case 0x4:
- if(!silent)printf("sd%d: non-media hardware failure\n ",
- unit);
- return(EIO);
- case 0x5:
- if(!silent)printf("sd%d: illegal request\n ",
- unit);
- return(EINVAL);
- case 0x6:
- /***********************************************\
- * If we are not open, then this is not an error *
- * as we don't have state yet. Either way, make *
- * sure that we don't have any residual state *
- \***********************************************/
- if(!silent)printf("sd%d: Unit attention.\n ", unit);
- sd_data[unit]->flags &= ~(SDVALID | SDHAVELABEL);
- if (sd_data[unit]->openparts)
- {
- return(EIO);
- }
- return(ESUCCESS); /* not an error if nothing's open */
- case 0x7:
- if(!silent)
- {
- printf("sd%d: attempted protection violation ",
- unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf("block no. %d (decimal)\n",info);
- }
- printf("\n");
- }
- return(EACCES);
- case 0x8:
- if(!silent)
- {
- printf("sd%d: block wrong state (format?)\n ",
- unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf("block no. %d (decimal)\n",info);
- }
- printf("\n");
- }
- return(EIO);
- case 0x9:
- if(!silent)printf("sd%d: vendor unique\n",
- unit);
- return(EIO);
- case 0xa:
- if(!silent)printf("sd%d: copy aborted\n ",
- unit);
- return(EIO);
- case 0xb:
- if(!silent)printf("sd%d: command aborted\n ",
- unit);
- return(EIO);
- case 0xc:
- if(!silent)
- {
- printf("sd%d: search returned\n ",
- unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf("block no. %d (decimal)\n",info);
- }
- printf("\n");
- }
- return(ESUCCESS);
- case 0xd:
- if(!silent)printf("sd%d: volume overflow\n ",
- unit);
- return(ENOSPC);
- case 0xe:
- if(!silent)
- {
- printf("sd%d: verify miscompare\n ",
- unit);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf("block no. %d (decimal)\n",info);
- }
- printf("\n");
- }
- return(EIO);
- case 0xf:
- if(!silent)printf("sd%d: unknown error key\n ",
- unit);
- return(EIO);
- }
- break;
- }
- default:
- {
- if(!silent)printf("sd%d: code %d\n",
- unit,
- sense->error_code & SSD_ERRCODE);
- if(sense->error_code & SSD_ERRCODE_VALID)
- if(!silent)printf("block no. %d (decimal)\n",
- (sense->ext.unextended.blockhi <<16)
- + (sense->ext.unextended.blockmed <<8)
- + (sense->ext.unextended.blocklow ));
- }
- return(EIO);
- }
+ return (int)sd->disklabel.d_partitions[part].p_size;
}
+#define SCSIDUMP 1
+#undef SCSIDUMP
+#define NOT_TRUSTED 1
-
-int
-sdsize(dev_t dev)
-{
- int unit = UNIT(dev), part = PARTITION(dev), val;
- struct sd_data *sd;
-
- if (unit >= NSD)
- return(-1);
-
- sd = sd_data[unit];
- if(!sd) return(-1);
- if((sd->flags & SDINIT) == 0) return(-1);
- if (sd == 0 || (sd->flags & SDHAVELABEL) == 0)
- val = sdopen (MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0);
- if ( val != 0 || sd->flags & SDWRITEPROT)
- return (-1);
-
- return((int)sd->disklabel.d_partitions[part].p_size);
-}
-/*#define SCSIDUMP*/
#ifdef SCSIDUMP
#include <vm/vm.h>
-/***********************************************************************\
-* dump all of physical memory into the partition specified, starting *
-* at offset 'dumplo' into the partition. *
-\***********************************************************************/
-static struct scsi_xfer sx;
-#define MAXTRANSFER 8 /* 1 page at a time */
-int
-sddump(dev_t dev) /* dump core after a system crash */
-{
+
+static struct scsi_xfer sx;
+#define MAXTRANSFER 8 /* 1 page at a time */
+
+/*
+ * dump all of physical memory into the partition specified, starting
+ * at offset 'dumplo' into the partition.
+ */
+errval
+sddump(dev_t dev)
+{ /* dump core after a system crash */
register struct sd_data *sd; /* disk unit to do the IO */
- long num; /* number of sectors to write */
- int unit, part, sdc;
- long blkoff, blknum, blkcnt;
- long nblocks;
+ int32 num; /* number of sectors to write */
+ u_int32 unit, part;
+ int32 blkoff, blknum, blkcnt = MAXTRANSFER;
+ int32 nblocks;
char *addr;
- struct scsi_rw_big cmd;
+ struct scsi_rw_big cmd;
extern int Maxmem;
- static sddoingadump = 0 ;
- extern caddr_t CADDR1; /* map the page we are about to write, here*/
- struct scsi_xfer *xs = &sx;
- int retval;
+ static int sddoingadump = 0;
+#define MAPTO CADDR1
+ extern caddr_t MAPTO; /* map the page we are about to write, here */
+ struct scsi_xfer *xs = &sx;
+ errval retval;
+ int c;
- addr = (char *) 0; /* starting address */
+ addr = (char *) 0; /* starting address */
/* toss any characters present prior to dump */
- while (sgetc(1))
- ;
+ while ((c = sgetc(1)) && (c != 0x100)); /*syscons and pccons differ */
/* size of memory to dump */
num = Maxmem;
- unit = UNIT(dev); /* eventually support floppies? */
- part = PARTITION(dev); /* file system */
+ unit = UNIT(dev); /* eventually support floppies? */
+ part = PARTITION(dev); /* file system */
/* check for acceptable drive number */
- if (unit >= NSD) return(ENXIO); /* 31 Jul 92*/
+ if (unit >= NSD)
+ return (ENXIO); /* 31 Jul 92 */
sd = sd_data[unit];
- if(!sd) return (ENXIO);
+ if (!sd)
+ return (ENXIO);
/* was it ever initialized etc. ? */
- if (!(sd->flags & SDINIT)) return (ENXIO);
- if (sd->flags & SDVALID != SDVALID) return (ENXIO) ;
- if (sd->flags & SDWRITEPROT) return (ENXIO);
+ if (!(sd->flags & SDINIT))
+ return (ENXIO);
+ if (sd->sc_link->flags & SDEV_MEDIA_LOADED != SDEV_MEDIA_LOADED)
+ return (ENXIO);
+ if (sd->flags & SDWRITEPROT)
+ return (ENXIO);
/* Convert to disk sectors */
- num = (u_long) num * NBPG / sd->disklabel.d_secsize;
+ num = (u_int32) num * NBPG / sd->disklabel.d_secsize;
/* check if controller active */
- if (sddoingadump) return(EFAULT);
+ if (sddoingadump)
+ return (EFAULT);
nblocks = sd->disklabel.d_partitions[part].p_size;
blkoff = sd->disklabel.d_partitions[part].p_offset;
/* check transfer bounds against partition size */
if ((dumplo < 0) || ((dumplo + num) > nblocks))
- return(EINVAL);
+ return (EINVAL);
- sddoingadump = 1 ;
+ sddoingadump = 1;
blknum = dumplo + blkoff;
- while (num > 0)
- {
- if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
- pmap_enter( kernel_pmap,
- CADDR1,
- trunc_page(addr),
- VM_PROT_READ,
- TRUE);
+ /* blkcnt = initialise_me; */
+ while (num > 0) {
+ pmap_enter(kernel_pmap,
+ MAPTO,
+ trunc_page(addr),
+ VM_PROT_READ,
+ TRUE);
#ifndef NOT_TRUSTED
- /*******************************************************\
- * Fill out the scsi command *
- \*******************************************************/
+ /*
+ * Fill out the scsi command
+ */
bzero(&cmd, sizeof(cmd));
- cmd.op_code = WRITE_BIG;
- cmd.addr_3 = (blknum & 0xff000000) >> 24;
- cmd.addr_2 = (blknum & 0xff0000) >> 16;
- cmd.addr_1 = (blknum & 0xff00) >> 8;
- cmd.addr_0 = blknum & 0xff;
- cmd.length2 = (blkcnt & 0xff00) >> 8;
- cmd.length1 = (blkcnt & 0xff);
- /*******************************************************\
- * Fill out the scsi_xfer structure *
- * Note: we cannot sleep as we may be an interrupt *
- \*******************************************************/
+ cmd.op_code = WRITE_BIG;
+ cmd.addr_3 = (blknum & 0xff000000) >> 24;
+ cmd.addr_2 = (blknum & 0xff0000) >> 16;
+ cmd.addr_1 = (blknum & 0xff00) >> 8;
+ cmd.addr_0 = blknum & 0xff;
+ cmd.length2 = (blkcnt & 0xff00) >> 8;
+ cmd.length1 = (blkcnt & 0xff);
+ /*
+ * Fill out the scsi_xfer structure
+ * Note: we cannot sleep as we may be an interrupt
+ * don't use scsi_scsi_cmd() as it may want
+ * to wait for an xs.
+ */
bzero(xs, sizeof(sx));
- xs->flags |= SCSI_NOMASK|SCSI_NOSLEEP|INUSE;
- xs->adapter = sd->ctlr;
- xs->targ = sd->targ;
- xs->lu = sd->lu;
- xs->retries = SD_RETRIES;
- xs->timeout = 10000;/* 10000 millisecs for a disk !*/
- xs->cmd = (struct scsi_generic *)&cmd;
- xs->cmdlen = sizeof(cmd);
- xs->resid = blkcnt * 512;
- xs->when_done = 0;
- xs->done_arg = unit;
- xs->done_arg2 = (int)xs;
- xs->error = XS_NOERROR;
- xs->bp = 0;
- xs->data = (u_char *)CADDR1;
- xs->datalen = blkcnt * 512;
-
- /*******************************************************\
- * Pass all this info to the scsi driver. *
- \*******************************************************/
- retval = (*(sd->sc_sw->scsi_cmd))(xs);
- switch(retval)
- {
- case SUCCESSFULLY_QUEUED:
- case HAD_ERROR:
- return(ENXIO); /* we said not to sleep! */
- case COMPLETE:
+ xs->flags |= SCSI_NOMASK | SCSI_NOSLEEP | INUSE;
+ xs->sc_link = sd->sc_link;
+ xs->retries = SD_RETRIES;
+ xs->timeout = 10000; /* 10000 millisecs for a disk ! */
+ xs->cmd = (struct scsi_generic *) &cmd;
+ xs->cmdlen = sizeof(cmd);
+ xs->resid = blkcnt * 512;
+ xs->error = XS_NOERROR;
+ xs->bp = 0;
+ xs->data = (u_char *) MAPTO;
+ xs->datalen = blkcnt * 512;
+
+ /*
+ * Pass all this info to the scsi driver.
+ */
+ retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs);
+ switch (retval) {
+ case SUCCESSFULLY_QUEUED:
+ case HAD_ERROR:
+ return (ENXIO); /* we said not to sleep! */
+ case COMPLETE:
break;
default:
- return(ENXIO); /* we said not to sleep! */
+ return (ENXIO); /* we said not to sleep! */
}
-#else NOT_TRUSTED
- /* lets just talk about this first...*/
- printf ("sd%d: dump addr 0x%x, blk %d\n",unit,addr,blknum);
-#endif NOT_TRUSTED
-
- if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ;
+#else /* NOT_TRUSTED */
+ /* lets just talk about this first... */
+ printf("sd%d: dump addr 0x%x, blk %d\n", unit, addr, blknum);
+#endif /* NOT_TRUSTED */
+
+ if ((unsigned) addr % (1024 * 1024) == 0)
+ printf("%d ", num / 2048);
/* update block count */
- num -= MAXTRANSFER;
- blknum += MAXTRANSFER ;
- (int) addr += 512 * MAXTRANSFER;
+ num -= blkcnt;
+ blknum += blkcnt;
+ (int) addr += 512 * blkcnt;
/* operator aborting dump? */
- if (sgetc(1))
- return(EINTR);
+ if ((c = sgetc(1)) && (c != 0x100))
+ return (EINTR);
}
- return(0);
+ return (0);
}
-#else SCSIDUMP
+#else /* SCSIDUMP */
+errval
sddump()
{
printf("\nsddump() -- not implemented\n");
- DELAY(20000000); /* 20 seconds */
- return(-1);
+ DELAY(60000000); /* 60 seconds */
+ return -1;
}
-#endif SCSIDUMP
-
+#endif /* SCSIDUMP */
diff --git a/sys/scsi/st.c b/sys/scsi/st.c
index e367389..08c8d467 100644
--- a/sys/scsi/st.c
+++ b/sys/scsi/st.c
@@ -12,13 +12,24 @@
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
*
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ * 1.15 is the last version to support MACH and OSF/1
+ */
+/* $Revision: 2.6 $ */
+
+/*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
* major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993
*
- * $Id: st.c,v 1.11 1993/10/16 17:21:10 rgrimes Exp $
+ * $Id: st.c,v 2.6 93/10/21 03:24:38 julian Exp Locker: julian $
*/
-
/*
* To do:
* work out some better way of guessing what a good timeout is going
@@ -41,886 +52,882 @@
#include <sys/user.h>
#include <sys/mtio.h>
-
#include <scsi/scsi_all.h>
#include <scsi/scsi_tape.h>
#include <scsi/scsiconf.h>
-
-long int ststrats,stqueues;
+u_int32 ststrats, stqueues;
/* Defines for device specific stuff */
#define PAGE_0_SENSE_DATA_SIZE 12
#define PAGESIZ 4096
#define DEF_FIXED_BSIZE 512
-#define STQSIZE 4
-#define ST_RETRIES 4
-
+#define ST_RETRIES 4 /* only on non IO commands */
#define MODE(z) ( (minor(z) & 0x03) )
#define DSTY(z) ( ((minor(z) >> 2) & 0x03) )
#define UNIT(z) ( (minor(z) >> 4) )
-
-#define DSTY3 3
-#define DSTY2 2
-#define DSTY1 1
+#define CTLMODE 3
#define SCSI_2_MAX_DENSITY_CODE 0x17 /* maximum density code specified
- in SCSI II spec. */
-/***************************************************************\
-* Define various devices that we know mis-behave in some way, *
-* and note how they are bad, so we can correct for them *
-\***************************************************************/
-struct modes
-{
- int quirks; /* same definitions as in rogues */
- char density;
- char spare[3];
+ * in SCSI II spec. */
+/*
+ * Define various devices that we know mis-behave in some way,
+ * and note how they are bad, so we can correct for them
+ */
+struct modes {
+ u_int32 blksiz;
+ u_int32 quirks; /* same definitions as in rogues */
+ char density;
+ char spare[3];
};
-struct rogues
-{
- char *name;
- char *manu;
- char *model;
- char *version;
- int quirks; /* valid for all modes */
- struct modes modes[4];
+
+struct rogues {
+ char *name;
+ char *manu;
+ char *model;
+ char *version;
+ u_int32 quirks; /* valid for all modes */
+ struct modes modes[4];
};
/* define behaviour codes (quirks) */
#define ST_Q_NEEDS_PAGE_0 0x00001
#define ST_Q_FORCE_FIXED_MODE 0x00002
#define ST_Q_FORCE_VAR_MODE 0x00004
-#define ST_Q_SNS_HLP 0x00008 /* must do READ for good MODE SENSE */
+#define ST_Q_SNS_HLP 0x00008 /* must do READ for good MODE SENSE */
#define ST_Q_IGNORE_LOADS 0x00010
-#define ST_Q_BLKSIZ 0x00020 /* variable-block media_blksiz > 0 */
+#define ST_Q_BLKSIZ 0x00020 /* variable-block media_blksiz > 0 */
-static struct rogues gallery[] = /* ends with an all null entry */
+static struct rogues gallery[] = /* ends with an all-null entry */
{
- { "Such an old device ", "pre-scsi", " unknown model ","????",
- 0,
- { {ST_Q_FORCE_FIXED_MODE,0}, /* minor 0,1,2,3 */
- {ST_Q_FORCE_FIXED_MODE,QIC_24}, /* minor 4,5,6,7 */
- {ST_Q_FORCE_VAR_MODE,HALFINCH_1600}, /* minor 8,9,10,11*/
- {ST_Q_FORCE_VAR_MODE,HALFINCH_6250} /* minor 12,13,14,15*/
- }
- },
- { "Tandberg tdc3600", "TANDBERG", " TDC 3600","????",
- ST_Q_NEEDS_PAGE_0,
- { {0,0}, /* minor 0,1,2,3*/
- {ST_Q_FORCE_VAR_MODE,QIC_525}, /* minor 4,5,6,7*/
- {0,QIC_150}, /* minor 8,9,10,11*/
- {0,QIC_120} /* minor 12,13,14,15*/
- }
- },
- { "Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462","-005",
- 0,
- { {ST_Q_SNS_HLP,0}, /* minor 0,1,2,3*/
- {ST_Q_SNS_HLP,QIC_525}, /* minor 4,5,6,7*/
- {0,QIC_150}, /* minor 8,9,10,11*/
- {0,QIC_120} /* minor 12,13,14,15*/
- }
- },
- { "Archive Viper 150", "ARCHIVE ", "VIPER 150","????",
- ST_Q_NEEDS_PAGE_0,
- { {0,0}, /* minor 0,1,2,3*/
- {0,QIC_150}, /* minor 4,5,6,7*/
- {0,QIC_120}, /* minor 8,9,10,11*/
- {0,QIC_24} /* minor 12,13,14,15*/
- }
- },
- { "Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????",
- 0,
- { {0,0}, /* minor 0,1,2,3*/
- {ST_Q_BLKSIZ,QIC_525}, /* minor 4,5,6,7*/
- {0,QIC_150}, /* minor 8,9,10,11*/
- {0,QIC_120} /* minor 12,13,14,15*/
- }
- },
- {(char *)0}
+ {"Such an old device ", "pre-scsi", " unknown model ", "????",
+ 0,
+ {
+ {512, ST_Q_FORCE_FIXED_MODE, 0}, /* minor 0,1,2,3 */
+ {512, ST_Q_FORCE_FIXED_MODE, QIC_24}, /* minor 4,5,6,7 */
+ {0, ST_Q_FORCE_VAR_MODE, HALFINCH_1600}, /* minor 8,9,10,11 */
+ {0, ST_Q_FORCE_VAR_MODE, HALFINCH_6250} /* minor 12,13,14,15 */
+ }
+ },
+ {"Tandberg tdc3600", "TANDBERG", " TDC 3600", "????",
+ ST_Q_NEEDS_PAGE_0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {0, ST_Q_FORCE_VAR_MODE, QIC_525}, /* minor 4,5,6,7 */
+ {0, 0, QIC_150}, /* minor 8,9,10,11 */
+ {0, 0, QIC_120} /* minor 12,13,14,15 */
+ }
+ },
+ {"Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462", "-005",
+ 0,
+ {
+ {0, ST_Q_SNS_HLP, 0}, /* minor 0,1,2,3 */
+ {0, ST_Q_SNS_HLP, QIC_525}, /* minor 4,5,6,7 */
+ {0, 0, QIC_150}, /* minor 8,9,10,11 */
+ {0, 0, QIC_120} /* minor 12,13,14,15 */
+ }
+ },
+ {"Archive Viper 150", "ARCHIVE ", "VIPER 150", "????",
+ ST_Q_NEEDS_PAGE_0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {0, 0, QIC_150}, /* minor 4,5,6,7 */
+ {0, 0, QIC_120}, /* minor 8,9,10,11 */
+ {0, 0, QIC_24} /* minor 12,13,14,15 */
+ }
+ },
+ {"Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????",
+ 0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {0, ST_Q_BLKSIZ, QIC_525}, /* minor 4,5,6,7 */
+ {0, 0, QIC_150}, /* minor 8,9,10,11 */
+ {0, 0, QIC_120} /* minor 12,13,14,15 */
+ }
+ },
+ {"WangDAT model 1300", "WangDAT ", "Model 1300", "????",
+ 0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {512, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 4,5,6,7 */
+ {1024, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 8,9,10,11 */
+ {0, ST_Q_FORCE_VAR_MODE, 0x13} /* minor 12,13,14,15 */
+ }
+ },
+ {(char *) 0}
};
-
-int ststrategy();
-void stminphys();
+errval st_space __P((u_int32 unit, int32 number, u_int32 what, u_int32 flags));
+errval st_rewind __P((u_int32 unit, boolean immed, u_int32 flags));
+errval st_mode_sense __P((u_int32 unit, u_int32 flags));
+errval st_decide_mode __P((u_int32 unit, boolean first_read));
+errval st_rd_blk_lim __P((u_int32 unit, u_int32 flags));
+errval st_touch_tape __P((u_int32 unit));
+errval st_write_filemarks __P((u_int32 unit, int32 number, u_int32 flags));
+errval st_load __P((u_int32 unit, u_int32 type, u_int32 flags));
+errval st_mode_select __P((u_int32 unit, u_int32 flags));
+void ststrategy();
+void stminphys();
+int32 st_chkeod();
+errval stattach();
+void ststart();
+void st_unmount();
+errval st_mount_tape();
+void st_loadquirks();
+void st_identify_drive();
+errval st_interpret_sense();
#define ESUCCESS 0
+#define NOEJECT 0
+#define EJECT 1
-#ifdef STDEBUG
-int st_debug = 1;
-#endif /*STDEBUG*/
-
-int stattach();
-int st_done();
-
-struct st_data
+struct scsi_device st_switch =
{
+ st_interpret_sense, /* check errors with us first */
+ ststart, /* we have a queue, and this is how we service it */
+ NULL,
+ NULL, /* use the default 'done' routine */
+ "st",
+ 0,
+ { 0, 0 }
+};
+
+struct st_data {
/*--------------------present operating parameters, flags etc.----------------*/
- int flags; /* see below */
- int blksiz; /* blksiz we are using */
- int density; /* present density */
- int quirks; /* quirks for the open mode */
- int last_dsty; /* last density used */
+ u_int32 flags; /* see below */
+ u_int32 blksiz; /* blksiz we are using */
+ u_int32 density; /* present density */
+ u_int32 quirks; /* quirks for the open mode */
+ u_int32 last_dsty; /* last density openned */
/*--------------------device/scsi parameters----------------------------------*/
- struct scsi_switch *sc_sw; /* address of scsi low level switch */
- int ctlr; /* so they know which one we want */
- int targ; /* our scsi target ID */
- int lu; /* our scsi lu */
+ struct scsi_link *sc_link; /* our link to the adpter etc. */
/*--------------------parameters reported by the device ----------------------*/
- int blkmin; /* min blk size */
- int blkmax; /* max blk size */
+ u_int32 blkmin; /* min blk size */
+ u_int32 blkmax; /* max blk size */
+ struct rogues *rogues; /* if we have a rogue entry */
/*--------------------parameters reported by the device for this media--------*/
- int numblks; /* nominal blocks capacity */
- int media_blksiz; /* 0 if not ST_FIXEDBLOCKS */
- int media_density; /* this is what it said when asked */
+ u_int32 numblks; /* nominal blocks capacity */
+ u_int32 media_blksiz; /* 0 if not ST_FIXEDBLOCKS */
+ u_int32 media_density; /* this is what it said when asked */
/*--------------------quirks for the whole drive------------------------------*/
- int drive_quirks; /* quirks of this drive */
+ u_int32 drive_quirks; /* quirks of this drive */
/*--------------------How we should set up when openning each minor device----*/
- struct modes modes[4]; /* plus more for each mode */
+ struct modes modes[4]; /* plus more for each mode */
+ u_int8 modeflags[4]; /* flags for the modes */
+#define DENSITY_SET_BY_USER 0x01
+#define DENSITY_SET_BY_QUIRK 0x02
+#define BLKSIZE_SET_BY_USER 0x04
+#define BLKSIZE_SET_BY_QUIRK 0x08
/*--------------------storage for sense data returned by the drive------------*/
- unsigned char sense_data[12]; /* additional sense data needed */
- /* for mode sense/select. */
- struct buf *buf_queue; /* the queue of pending IO operations */
- struct scsi_xfer scsi_xfer; /* The scsi xfer struct for this drive*/
- int xfer_block_wait; /* whether there is a process waiting */
-}*st_data[NST];
+ unsigned char sense_data[12]; /*
+ * additional sense data needed
+ * for mode sense/select.
+ */
+ struct buf *buf_queue; /* the queue of pending IO operations */
+ struct scsi_xfer scsi_xfer; /* scsi xfer struct for this drive */
+ u_int32 xfer_block_wait; /* is a process waiting? */
+} *st_data[NST];
+
#define ST_INITIALIZED 0x01
#define ST_INFO_VALID 0x02
#define ST_OPEN 0x04
-#define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */
-#define ST_WRITTEN 0x10 /* data have been written, EOD needed */
+#define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */
+#define ST_WRITTEN 0x10 /* data have been written, EOD needed */
#define ST_FIXEDBLOCKS 0x20
#define ST_AT_FILEMARK 0x40
-#define ST_EIO_PENDING 0x80 /* we couldn't report it then (had data)*/
-#define ST_AT_BOM 0x100 /* ops history suggests Beg of Medium */
-#define ST_READONLY 0x200 /* st_mode_sense says write protected */
-#define ST_FM_WRITTEN 0x400 /* EOF file mark written -- */
- /* used with ~ST_WRITTEN to indicate */
- /* that multiple file marks have been */
- /* written */
-#define ST_BLANK_READ 0x800 /* BLANK CHECK encountered already */
-#define ST_2FM_AT_EOD 0x1000 /* write 2 file marks at EOD */
+#define ST_EIO_PENDING 0x80 /* we couldn't report it then (had data) */
+#define ST_NEW_MOUNT 0x100 /* still need to decide mode */
+#define ST_READONLY 0x200 /* st_mode_sense says write protected */
+#define ST_FM_WRITTEN 0x400 /*
+ * EOF file mark written -- used with
+ * ~ST_WRITTEN to indicate that multiple file
+ * marks have been written
+ */
+#define ST_BLANK_READ 0x800 /* BLANK CHECK encountered already */
+#define ST_2FM_AT_EOD 0x1000 /* write 2 file marks at EOD */
+#define ST_MOUNTED 0x2000 /* Device is presently mounted */
#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
-#define ST_PER_OPEN ST_OPEN
-#define ST_PER_MEDIA (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
- ST_FIXEDBLOCKS | ST_AT_BOM | ST_READONLY | \
+#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
+ ST_FIXEDBLOCKS | ST_READONLY | \
ST_FM_WRITTEN | ST_2FM_AT_EOD | ST_PER_ACTION)
-static int next_st_unit = 0;
-/***********************************************************************\
-* The routine called by the low level scsi routine when it discovers *
-* A device suitable for this driver *
-\***********************************************************************/
+static u_int32 next_st_unit = 0;
-int stattach(ctlr,targ,lu,scsi_switch)
-struct scsi_switch *scsi_switch;
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * A device suitable for this driver
+ */
+
+errval
+stattach(sc_link)
+ struct scsi_link *sc_link;
{
- int unit,i;
+ u_int32 unit;
struct st_data *st;
-#ifdef STDEBUG
- if(scsi_debug & PRINTROUTINES) printf("stattach: ");
-#endif /*STDEBUG*/
- /*******************************************************\
- * Check we have the resources for another drive *
- \*******************************************************/
+ SC_DEBUG(sc_link, SDEV_DB2, ("stattach: "));
+ /*
+ * Check we have the resources for another drive
+ */
unit = next_st_unit++;
- if( unit >= NST)
- {
+
+ if (unit >= NST) {
printf("Too many scsi tapes..(%d > %d) reconfigure kernel\n",
- (unit + 1),NST);
- return(0);
+ (unit + 1), NST);
+ return 0;
}
- if(st_data[unit])
- {
- printf("st%d: Already has storage!\n",unit);
- return(0);
+ if (st_data[unit]) {
+ printf("st%d: Already has storage!\n", unit);
+ return 0;
}
- st = st_data[unit] = malloc(sizeof(struct st_data),M_DEVBUF,M_NOWAIT);
- if(!st)
- {
- printf("st%d: malloc failed in st.c\n",unit);
- return(0);
+ sc_link->device = &st_switch;
+ sc_link->dev_unit = unit;
+ st = st_data[unit] = malloc(sizeof(struct st_data), M_DEVBUF, M_NOWAIT);
+ if (!st) {
+ printf("st%d: malloc failed in st.c\n", unit);
+ return 0;
}
- bzero(st,sizeof(struct st_data));
-
- /*******************************************************\
- * Store information needed to contact our base driver *
- \*******************************************************/
- st->sc_sw = scsi_switch;
- st->ctlr = ctlr;
- st->targ = targ;
- st->lu = lu;
-
- /*******************************************************\
- * Store information about default densities *
- \*******************************************************/
- st->modes[DSTY1].density = QIC_525;
- st->modes[DSTY2].density = QIC_150;
- st->modes[DSTY3].density = QIC_120;
-
- /*******************************************************\
- * Check if the drive is a known criminal and take *
- * Any steps needed to bring it into line *
- \*******************************************************/
+ bzero(st, sizeof(struct st_data));
+
+ /*
+ * Store information needed to contact our base driver
+ */
+ st->sc_link = sc_link;
+
+ /*
+ * Check if the drive is a known criminal and take
+ * Any steps needed to bring it into line
+ */
st_identify_drive(unit);
- /*******************************************************\
- * Use the subdriver to request information regarding *
- * the drive. We cannot use interrupts yet, so the *
- * request must specify this. *
- \*******************************************************/
- if(st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT))
- {
+ /*
+ * Use the subdriver to request information regarding
+ * the drive. We cannot use interrupts yet, so the
+ * request must specify this.
+ */
+ if (st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
printf("st%d: drive offline\n", unit);
- }
- else
- {
- if(!st_test_ready(unit,SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT))
- {
- printf("st%d: density code 0x%x, ",
- unit, st->media_density);
- if (st->media_blksiz)
- {
+ } else {
+ printf("st%d: density code 0x%x, ", unit, st->media_density);
+ if (!scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
+ if (st->media_blksiz) {
printf("%d-byte", st->media_blksiz);
- }
- else
- {
+ } else {
printf("variable");
}
printf(" blocks, write-%s\n",
- st->flags & ST_READONLY ? "protected" : "enabled");
- }
- else
- {
- printf("st%d: drive empty\n", unit);
+ (st->flags & ST_READONLY) ? "protected" : "enabled");
+ } else {
+ printf(" drive empty\n");
}
}
- /*******************************************************\
- * Set up the bufs for this device *
- \*******************************************************/
- st->buf_queue = 0;
-
-
+ /*
+ * Set up the buf queue for this device
+ */
+ st->buf_queue = 0;
st->flags |= ST_INITIALIZED;
- return;
-
+ return 0;
}
-/***********************************************************************\
-* Use the identify routine in 'scsiconf' to get drive info so we can *
-* Further tailor our behaviour. *
-\***********************************************************************/
-
+/*
+ * Use the inquiry routine in 'scsi_base' to get drive info so we can
+ * Further tailor our behaviour.
+ */
+void
st_identify_drive(unit)
-int unit;
+ u_int32 unit;
{
-
- struct st_data *st = st_data[unit];
- struct scsi_inquiry_data inqbuf;
- struct rogues *finger;
- char manu[32];
- char model[32];
- char model2[32];
- char version[32];
- int model_len;
-
-
- /*******************************************************\
- * Get the device type information *
- \*******************************************************/
- if (scsi_inquire(st->ctlr, st->targ, st->lu, st->sc_sw, &inqbuf,
- SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != COMPLETE)
- {
+ struct st_data *st = st_data[unit];
+ struct scsi_inquiry_data inqbuf;
+ struct rogues *finger;
+ char manu[32];
+ char model[32];
+ char model2[32];
+ char version[32];
+ u_int32 model_len;
+
+ /*
+ * Get the device type information
+ */
+ if (scsi_inquire(st->sc_link, &inqbuf,
+ SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != 0) {
printf("st%d: couldn't get device type, using default\n", unit);
return;
}
- if((inqbuf.version & SID_ANSII) == 0)
- {
- /***********************************************\
- * If not advanced enough, use default values *
- \***********************************************/
- strncpy(manu,"pre-scsi",8);manu[8]=0;
- strncpy(model," unknown model ",16);model[16]=0;
- strncpy(version,"????",4);version[4]=0;
+ if ((inqbuf.version & SID_ANSII) == 0) {
+ /*
+ * If not advanced enough, use default values
+ */
+ strncpy(manu, "pre-scsi", 8);
+ manu[8] = 0;
+ strncpy(model, " unknown model ", 16);
+ model[16] = 0;
+ strncpy(version, "????", 4);
+ version[4] = 0;
+ } else {
+ strncpy(manu, inqbuf.vendor, 8);
+ manu[8] = 0;
+ strncpy(model, inqbuf.product, 16);
+ model[16] = 0;
+ strncpy(version, inqbuf.revision, 4);
+ version[4] = 0;
}
- else
- {
- strncpy(manu,inqbuf.vendor,8);manu[8]=0;
- strncpy(model,inqbuf.product,16);model[16]=0;
- strncpy(version,inqbuf.revision,4);version[4]=0;
- }
-
- /*******************************************************\
- * Load the parameters for this kind of device, so we *
- * treat it as appropriate for each operating mode *
- * Only check the number of characters in the array's *
- * model entry, not the entire model string returned. *
- \*******************************************************/
+
+ /*
+ * Load the parameters for this kind of device, so we
+ * treat it as appropriate for each operating mode.
+ * Only check the number of characters in the array's
+ * model entry, not the entire model string returned.
+ */
finger = gallery;
- while(finger->name)
- {
+ while (finger->name) {
model_len = 0;
- while(finger->model[model_len] && (model_len < 32))
- {
+ while (finger->model[model_len] && (model_len < 32)) {
model2[model_len] = model[model_len];
model_len++;
}
model2[model_len] = 0;
- if ((strcmp(manu, finger->manu) == 0 )
- && (strcmp(model2, finger->model) == 0 ||
- strcmp("????????????????", finger->model) == 0)
- && (strcmp(version, finger->version) == 0 ||
- strcmp("????", finger->version) == 0))
- {
- printf("st%d: %s is a known rogue\n", unit,finger->name);
- st->modes[0] = finger->modes[0];
- st->modes[1] = finger->modes[1];
- st->modes[2] = finger->modes[2];
- st->modes[3] = finger->modes[3];
- st->drive_quirks= finger->quirks;
- st->quirks = finger->quirks; /*start value*/
+ if ((strcmp(manu, finger->manu) == 0)
+ && (strcmp(model2, finger->model) == 0 ||
+ strcmp("????????????????", finger->model) == 0)
+ && (strcmp(version, finger->version) == 0 ||
+ strcmp("????", finger->version) == 0)) {
+ printf("st%d: %s is a known rogue\n", unit, finger->name);
+ st->rogues = finger;
+ st->drive_quirks = finger->quirks;
+ st->quirks = finger->quirks; /*start value */
+ st_loadquirks(st);
break;
- }
- else
- {
+ } else {
finger++; /* go to next suspect */
}
}
}
-/*******************************************************\
-* open the device. *
-\*******************************************************/
+/*
+ * initialise the subdevices to the default (QUIRK) state.
+ * this will remove any setting made by the system operator or previous
+ * operations.
+ */
+void
+st_loadquirks(st)
+ struct st_data *st;
+{
+ int i;
+ struct modes *mode;
+ struct modes *mode2;
+
+ if (!st->rogues)
+ return;
+ mode = st->rogues->modes;
+ mode2 = st->modes;
+ for (i = 0; i < 4; i++) {
+ bzero(mode2, sizeof(struct modes));
+ st->modeflags[i] &= ~(BLKSIZE_SET_BY_QUIRK
+ | DENSITY_SET_BY_QUIRK
+ | BLKSIZE_SET_BY_USER
+ | DENSITY_SET_BY_USER);
+ if (mode->blksiz && ((mode->quirks | st->drive_quirks)
+ & (ST_Q_FORCE_FIXED_MODE))) {
+ mode2->blksiz = mode->blksiz;
+ st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK;
+ } else {
+ if ((mode->quirks | st->drive_quirks)
+ & ST_Q_FORCE_VAR_MODE) {
+ mode2->blksiz = 0;
+ st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK;
+ }
+ }
+ if (mode->density) {
+ mode2->density = mode->density;
+ st->modeflags[i] |= DENSITY_SET_BY_QUIRK;
+ }
+ mode++;
+ mode2++;
+ }
+}
+
+/*
+ * open the device.
+ */
+errval
stopen(dev, flags)
-int dev, flags;
+ dev_t dev;
+ u_int32 flags;
{
- int unit,mode,dsty;
- int errno = 0;
+ u_int32 unit, mode, dsty;
+ errval errno = 0;
struct st_data *st;
+ struct scsi_link *sc_link;
unit = UNIT(dev);
mode = MODE(dev);
dsty = DSTY(dev);
- /*******************************************************\
- * Check the unit is legal *
- \*******************************************************/
- if ( unit >= NST )
- {
- return(ENXIO);
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= NST) {
+ return (ENXIO);
}
st = st_data[unit];
- /*******************************************************\
- * Make sure the device has been initialised *
- \*******************************************************/
+ /*
+ * Make sure the device has been initialised
+ */
if ((st == NULL) || (!(st->flags & ST_INITIALIZED)))
- return(ENXIO);
-
- /*******************************************************\
- * Only allow one at a time *
- \*******************************************************/
- if(st->flags & ST_OPEN)
- {
- return(ENXIO);
+ return (ENXIO);
+
+ sc_link = st->sc_link;
+ SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n"
+ ,dev, unit, NST));
+ /*
+ * Only allow one at a time
+ */
+ if (st->flags & ST_OPEN) {
+ return (ENXIO);
}
-
- /*******************************************************\
- * Throw out a dummy instruction to catch 'Unit attention*
- * errors (the error handling will invalidate all our *
- * device info if we get one, but otherwise, ignore it *
- \*******************************************************/
- st_test_ready(unit, SCSI_SILENT);
-
- /***************************************************************\
- * Check that the device is ready to use (media loaded?) *
- * This time take notice of the return result *
- \***************************************************************/
- if(errno = (st_test_ready(unit,0)))
- {
- printf("st%d: not ready\n",unit);
- return(errno);
+ /*
+ * Throw out a dummy instruction to catch 'Unit attention
+ * errors (the error handling will invalidate all our
+ * device info if we get one, but otherwise, ignore it)
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ sc_link->flags |= SDEV_OPEN; /* unit attn are now errors */
+ /*
+ * If the mode is 3 (e.g. minor = 3,7,11,15)
+ * then the device has been openned to set defaults
+ * This mode does NOT ALLOW I/O, only ioctls
+ */
+ if (mode == CTLMODE)
+ return 0;
+
+ /*
+ * Check that the device is ready to use (media loaded?)
+ * This time take notice of the return result
+ */
+ if (errno = (scsi_test_unit_ready(sc_link, 0))) {
+ printf("st%d: not ready\n", unit);
+ st_unmount(unit, NOEJECT);
+ return (errno);
}
-
- /*******************************************************\
- * Set up the mode flags according to the minor number *
- * ensure all open flags are in a known state *
- * if it's a different mode, dump all cached parameters *
- \*******************************************************/
- if(st->last_dsty != dsty || !(st->flags & ST_INFO_VALID))
- {
- st->flags &= ~ST_INFO_VALID;
- st->last_dsty = dsty;
- st->quirks = st->drive_quirks | st->modes[dsty].quirks;
- st->density = st->modes[dsty].density;
+ /*
+ * if it's a different mode, or if the media has been
+ * invalidated, unmount the tape from the previous
+ * session but continue with open processing
+ */
+ if ((st->last_dsty != dsty)
+ || (!(sc_link->flags & SDEV_MEDIA_LOADED))) {
+ st_unmount(unit, NOEJECT);
}
- st->flags &= ~ST_PER_OPEN;
-
-#ifdef STDEBUG
- if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
- printf("stopen: dev=0x%x (unit %d (of %d))\n"
- , dev, unit, NST);
-#endif /*STDEBUG*/
- /***************************************************************\
- * If the media is new, then make sure we give it a chance to *
- * to do a 'load' instruction. *
- \***************************************************************/
- if(!(st->flags & ST_INFO_VALID)) /* is media new? */
- {
- if(errno = st_load(unit,LD_LOAD,0))
- {
- return(errno);
- }
- st_test_ready(unit,0);
- if(st->quirks & ST_Q_SNS_HLP)
- {
- /***********************************************\
- * The quirk here is that the drive returns some *
- * value to st_mode_sense incorrectly until the *
- * tape has actually passed by the head. *
- * *
- * The method is to set the drive to large *
- * fixed-block state (user-specified density and *
- * 1024-byte blocks), then read and rewind to *
- * get it to sense the tape. If that doesn't *
- * work, try 512-byte fixed blocks. If that *
- * doesn't work, as a last resort, try variable- *
- * length blocks. The result will be the *
- * ability to do an accurate st_mode_sense. *
- * *
- * We pretend not to be at beginning of medium *
- * to keep st_read from calling st_decide_mode. *
- * *
- * We know we can do a rewind because we just *
- * did a load, which implies rewind. Rewind *
- * seems preferable to space backward if we have *
- * a virgin tape. *
- * *
- * The rest of the code for this quirk is in ILI *
- * processing and BLANK CHECK error processing, *
- * both part of st_interpret_sense. *
- \***********************************************/
- char *buf;
- int readsiz;
-
- buf = malloc(1024,M_TEMP,M_NOWAIT);
- if(!buf) return(ENOMEM);
-
- if (errno = st_mode_sense(unit, 0))
- {
- goto bad;
- }
- st->blksiz = 1024;
- do {
- switch (st->blksiz)
- {
- case 512:
- case 1024:
- readsiz = st->blksiz;
- st->flags |= ST_FIXEDBLOCKS;
- break;
- default:
- readsiz = 1;
- st->flags &= ~ST_FIXEDBLOCKS;
- }
- if (errno = st_mode_select(unit, 0))
- {
- goto bad;
- }
- st->flags &= ~ST_AT_BOM;
- st_read(unit, buf, readsiz, SCSI_SILENT);
- if (errno = st_rewind(unit, FALSE, 0))
- {
-bad: free(buf,M_TEMP);
- return(errno);
- }
- } while (readsiz != 1 && readsiz > st->blksiz);
- free(buf,M_TEMP);
- }
- }
-
- /*******************************************************\
- * Load the physical device parameters *
- * loads: blkmin, blkmax *
- \*******************************************************/
- if(errno = st_rd_blk_lim(unit,0))
- {
- return(errno);
- }
-
- /*******************************************************\
- * Load the media dependent parameters *
- * includes: media_blksiz,media_density,numblks *
- \*******************************************************/
- if(errno = st_mode_sense(unit,0))
- {
- return(errno);
- }
-
- if (!(st->flags & ST_INFO_VALID) && dsty == 0)
- {
- /*******************************************************\
- * If the user defaulted the density, use the drive's *
- * opinion of it. *
- \*******************************************************/
- st->quirks = st->drive_quirks;
- st->density = st->media_density;
- do {
- if (st->density == st->modes[dsty].density)
- {
- st->quirks |= st->modes[dsty].quirks;
-#ifdef STDEBUG
- if(st_debug) printf("selected density %d\n", dsty);
-#endif /*STDEBUG*/
- break; /* only out of the loop*/
- }
- } while (++dsty < 4);
- /*******************************************************\
- * If dsty got to 4, the drive must have reported a *
- * density which isn't in our density list (e.g. QIC-24 *
- * for a default drive). We can handle that, except *
- * there'd better be no density-specific quirks in the *
- * drive's behavior. *
- \*******************************************************/
- }
-
- /***************************************************************\
- * Decide whether or not to write two file marks to signify end- *
- * of-data. Make the decision as a function of density. If *
- * the decision is not to use a second file mark, the SCSI BLANK *
- * CHECK condition code will be recognized as end-of-data when *
- * first read. *
- \***************************************************************/
- switch (st->density)
- {
-/* case 8 mm: What is the SCSI density code for 8 mm, anyway? */
- case QIC_11:
- case QIC_24:
- case QIC_120:
- case QIC_150:
- case QIC_525:
- case QIC_1320:
- st->flags &= ~ST_2FM_AT_EOD;
- break;
- default:
- st->flags |= ST_2FM_AT_EOD;
+ /*
+ * If we are not mounted, then we should start a new
+ * mount session.
+ */
+ if (!(st->flags & ST_MOUNTED)) {
+ st_mount_tape(dev, flags);
+ st->last_dsty = dsty;
}
-
- /***************************************************************\
- * Make sure that a tape opened in write-only mode will have *
- * file marks written on it. This is the only way to write a *
- * zero-length file on tape. *
- \***************************************************************/
+ /*
+ * Make sure that a tape opened in write-only mode will have
+ * file marks written on it when closed, even if not written to.
+ * This is for SUN compatibility
+ */
if ((flags & O_ACCMODE) == FWRITE)
st->flags |= ST_WRITTEN;
- st->flags |= ST_INFO_VALID;
-
- st_prevent(unit,PR_PREVENT,0); /* who cares if it fails? */
-
-#ifdef STDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("Params loaded ");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB2, ("Open complete\n"));
st->flags |= ST_OPEN;
- return(0);
+ return (0);
}
-/*******************************************************\
-* close the device.. only called if we are the LAST *
-* occurence of an open device *
-\*******************************************************/
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval
stclose(dev)
+ dev_t dev;
{
- unsigned char unit,mode;
- struct st_data *st;
+ unsigned char unit, mode;
+ struct st_data *st;
+ struct scsi_link *sc_link;
unit = UNIT(dev);
mode = MODE(dev);
st = st_data[unit];
-
-#ifdef STDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("Closing device");
-#endif /*STDEBUG*/
- switch(mode)
- {
- case 0:
- st_rewind(unit,FALSE,SCSI_SILENT);
- st_prevent(unit,PR_ALLOW,SCSI_SILENT);
- st->flags &= ~ST_PER_MEDIA;
- break;
- case 1: /*non rewind*/
- if((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
- st_write_filemarks(unit, 1, 0);
+ sc_link = st->sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("closing\n"));
+ if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
+ st_write_filemarks(unit, 1, 0);
+ switch (mode & 0x3) {
+ case 0:
+ case 3: /* for now */
+ st_unmount(unit, NOEJECT);
break;
- case 2:
- st_rewind(unit,FALSE,SCSI_SILENT);
- st_prevent(unit,PR_ALLOW,SCSI_SILENT);
- st_load(unit,LD_UNLOAD,SCSI_SILENT);
- st->flags &= ~ST_PER_MEDIA;
+ case 1: /*leave mounted unless media seems to have been removed */
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ st_unmount(unit, NOEJECT);
+ }
break;
- case 3:/* a bit silly really */
- st_prevent(unit,PR_ALLOW,SCSI_SILENT);
- st_load(unit,LD_UNLOAD,SCSI_SILENT);
- st->flags &= ~ST_PER_MEDIA;
+ case 2:
+ st_unmount(unit, EJECT);
break;
- default:
- printf("st%d: close: Bad mode (minor number)%d how's it open?\n"
- ,unit,mode);
- return(EINVAL);
}
- st->flags &= ~ST_PER_OPEN;
- return(0);
+ sc_link->flags &= ~SDEV_OPEN;
+ st->flags &= ~ST_OPEN;
+ return (0);
}
-/***************************************************************\
-* Given all we know about the device, media, mode, 'quirks' and *
-* initial operation, make a decision as to how we should be set *
-* up. First, choose the density, then variable/fixed blocks. *
-\***************************************************************/
-st_decide_mode(unit, first_read)
-int unit, first_read;
+/*
+ * Start a new mount session.
+ * Copy in all the default parameters from the selected device mode.
+ * and try guess any that seem to be defaulted.
+ */
+errval
+st_mount_tape(dev, flags)
+ dev_t dev;
+ u_int32 flags;
{
- int dsty, error;
- struct st_data *st = st_data[unit];
+ u_int32 unit, mode, dsty;
+ struct st_data *st;
+ struct scsi_link *sc_link;
+ errval errno = 0;
- /***************************************************************\
- * First, if our information about the tape is out of date, get *
- * new information. *
- \***************************************************************/
- if (!(st->flags & ST_INFO_VALID))
- {
- if (error = st_mode_sense(unit, 0))
- return (error);
- st->flags |= ST_INFO_VALID;
+ unit = UNIT(dev);
+ mode = MODE(dev);
+ dsty = DSTY(dev);
+ st = st_data[unit];
+ sc_link = st->sc_link;
+
+ if (st->flags & ST_MOUNTED)
+ return 0;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("mounting\n "));
+ st->flags |= ST_NEW_MOUNT;
+ st->quirks = st->drive_quirks | st->modes[dsty].quirks;
+ /*
+ * If the media is new, then make sure we give it a chance to
+ * to do a 'load' instruction. ( We assume it is new)
+ */
+ if (errno = st_load(unit, LD_LOAD, 0)) {
+ return (errno);
}
-#ifdef STDEBUG
- if(st_debug) printf("starting mode decision\n");
-#endif /*STDEBUG*/
-
- /***************************************************************\
- * If the user has already specified fixed or variable-length *
- * blocks using an ioctl, just believe him. OVERRIDE ALL *
- \***************************************************************/
- if (st->flags & ST_BLOCK_SET)
- {
-#ifdef STDEBUG
- if(st_debug) printf("user has specified %s mode\n",
- st->flags & ST_FIXEDBLOCKS ? "fixed" : "variable");
-#endif /*STDEBUG*/
- goto done;
+ /*
+ * Throw another dummy instruction to catch
+ * 'Unit attention' errors. Some drives appear to give
+ * these after doing a Load instruction.
+ * (noteably some DAT drives)
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ /*
+ * Some devices can't tell you much until they have been
+ * asked to look at the media. This quirk does this.
+ */
+ if (st->quirks & ST_Q_SNS_HLP) {
+ if (errno = st_touch_tape(unit))
+ return errno;
+ }
+ /*
+ * Load the physical device parameters
+ * loads: blkmin, blkmax
+ */
+ if (errno = st_rd_blk_lim(unit, 0)) {
+ return errno;
+ }
+ /*
+ * Load the media dependent parameters
+ * includes: media_blksiz,media_density,numblks
+ * As we have a tape in, it should be reflected here.
+ * If not you may need the "quirk" above.
+ */
+ if (errno = st_mode_sense(unit, 0)) {
+ return errno;
+ }
+ /*
+ * If we have gained a permanent density from somewhere,
+ * then use it in preference to the one supplied by
+ * default by the driver.
+ */
+ if (st->modeflags[dsty] & (DENSITY_SET_BY_QUIRK | DENSITY_SET_BY_USER)) {
+ st->density = st->modes[dsty].density;
+ } else {
+ st->density = st->media_density;
+ }
+ /*
+ * If we have gained a permanent blocksize
+ * then use it in preference to the one supplied by
+ * default by the driver.
+ */
+ st->flags &= ~ST_FIXEDBLOCKS;
+ if (st->modeflags[dsty] & (BLKSIZE_SET_BY_QUIRK | BLKSIZE_SET_BY_USER)) {
+ st->blksiz = st->modes[dsty].blksiz;
+ if (st->blksiz) {
+ st->flags |= ST_FIXEDBLOCKS;
+ }
+ } else {
+ if (errno = st_decide_mode(unit, FALSE)) {
+ return errno;
+ }
+ }
+ if (errno = st_mode_select(unit, 0)) {
+ printf("st%d: Cannot set selected mode", unit);
+ return errno;
}
+ scsi_prevent(sc_link, PR_PREVENT, 0); /* who cares if it fails? */
+ st->flags &= ~ST_NEW_MOUNT;
+ st->flags |= ST_MOUNTED;
+ sc_link->flags |= SDEV_MEDIA_LOADED; /* move earlier? */
- /***************************************************************\
- * If the user hasn't already specified fixed or variable-length *
- * blocks and the block size (zero if variable-length), we'll *
- * have to try to figure them out ourselves. *
- * *
- * Our first shot at a method is, "The quirks made me do it!" *
- \***************************************************************/
- switch (st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE))
- {
- case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE):
- printf("st%d: bad quirks\n",unit);
+ return 0;
+}
+
+/*
+ * End the present mount session.
+ * Rewind, and optionally eject the tape.
+ * Reset various flags to indicate that all new
+ * operations require another mount operation
+ */
+void
+st_unmount(int unit, boolean eject)
+{
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
+ int32 nmarks;
+
+ if (!(st->flags & ST_MOUNTED))
+ return;
+ SC_DEBUG(sc_link, SDEV_DB1, ("unmounting\n"));
+ st_chkeod(unit, FALSE, &nmarks, SCSI_SILENT);
+ st_rewind(unit, FALSE, SCSI_SILENT);
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
+ if (eject) {
+ st_load(unit, LD_UNLOAD, SCSI_SILENT);
+ }
+ st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT);
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+}
+
+/*
+ * Given all we know about the device, media, mode, 'quirks' and
+ * initial operation, make a decision as to how we should be set
+ * to run (regarding blocking and EOD marks)
+ */
+errval
+st_decide_mode(unit, first_read)
+ u_int32 unit;
+ boolean first_read;
+{
+ struct st_data *st = st_data[unit];
+#ifdef SCSIDEBUG
+ struct scsi_link *sc_link = st->sc_link;
+#endif
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("starting block mode decision\n"));
+
+ /*
+ * If the user hasn't already specified fixed or variable-length
+ * blocks and the block size (zero if variable-length), we'll
+ * have to try to figure them out ourselves.
+ *
+ * Our first shot at a method is, "The quirks made me do it!"
+ */
+ switch (st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE)) {
+ case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE):
+ printf("st%d: bad quirks\n", unit);
return (EINVAL);
- case ST_Q_FORCE_FIXED_MODE:
+ case ST_Q_FORCE_FIXED_MODE: /*specified fixed, but not what size */
st->flags |= ST_FIXEDBLOCKS;
if (st->blkmin && (st->blkmin == st->blkmax))
st->blksiz = st->blkmin;
- else if(st->media_blksiz > 0)
+ else if (st->media_blksiz > 0)
st->blksiz = st->media_blksiz;
else
st->blksiz = DEF_FIXED_BSIZE;
-#ifdef STDEBUG
- if(st_debug) printf("Quirks force fixed mode\n");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force fixed mode(%d)\n",
+ st->blksiz));
goto done;
- case ST_Q_FORCE_VAR_MODE:
+ case ST_Q_FORCE_VAR_MODE:
st->flags &= ~ST_FIXEDBLOCKS;
st->blksiz = 0;
-#ifdef STDEBUG
- if(st_debug) printf("Quirks force variable mode\n");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force variable mode\n"));
goto done;
}
-
- /***************************************************************\
- * If the drive can only handle fixed-length blocks and only at *
- * one size, perhaps we should just do that. *
- \***************************************************************/
- if (st->blkmin && (st->blkmin == st->blkmax))
- {
+ /*
+ * If the drive can only handle fixed-length blocks and only at
+ * one size, perhaps we should just do that.
+ */
+ if (st->blkmin && (st->blkmin == st->blkmax)) {
st->flags |= ST_FIXEDBLOCKS;
st->blksiz = st->blkmin;
-#ifdef STDEBUG
- if(st_debug) printf("blkmin == blkmax of %d\n",st->blkmin);
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("blkmin == blkmax of %d\n", st->blkmin));
goto done;
}
-
- /***************************************************************\
- * If the tape density mandates use of fixed or variable-length *
- * blocks, comply. *
- \***************************************************************/
- switch (st->density)
- {
- case HALFINCH_800:
- case HALFINCH_1600:
- case HALFINCH_6250:
- case DDS:
+ /*
+ * If the tape density mandates (or even suggests) use of fixed
+ * or variable-length blocks, comply.
+ */
+ switch (st->density) {
+ case HALFINCH_800:
+ case HALFINCH_1600:
+ case HALFINCH_6250:
+ case DDS:
st->flags &= ~ST_FIXEDBLOCKS;
st->blksiz = 0;
-#ifdef STDEBUG
- if(st_debug) printf("density specified variable\n");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3, ("density specified variable\n"));
goto done;
- case QIC_11:
- case QIC_24:
- case QIC_120:
- case QIC_150:
+ case QIC_11:
+ case QIC_24:
+ case QIC_120:
+ case QIC_150:
+ case QIC_525:
+ case QIC_1320:
st->flags |= ST_FIXEDBLOCKS;
- if (st->media_blksiz > 0)
+ if (st->media_blksiz > 0) {
st->blksiz = st->media_blksiz;
- else
+ } else {
st->blksiz = DEF_FIXED_BSIZE;
-#ifdef STDEBUG
- if(st_debug) printf("density specified fixed\n");
-#endif /*STDEBUG*/
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("density specified fixed\n"));
goto done;
}
-
- /***************************************************************\
- * If we're about to read the tape, perhaps we should choose *
- * fixed or variable-length blocks and block size according to *
- * what the drive found on the tape. *
- \***************************************************************/
- if (first_read && (!(st->quirks & ST_Q_BLKSIZ) || st->media_blksiz == 0
- || st->media_blksiz == DEF_FIXED_BSIZE || st->media_blksiz == 1024))
- {
- if (st->media_blksiz == 0)
+ /*
+ * If we're about to read the tape, perhaps we should choose
+ * fixed or variable-length blocks and block size according to
+ * what the drive found on the tape.
+ */
+ if (first_read
+ && (!(st->quirks & ST_Q_BLKSIZ)
+ || (st->media_blksiz == 0)
+ || (st->media_blksiz == DEF_FIXED_BSIZE)
+ || (st->media_blksiz == 1024))) {
+ if (st->media_blksiz == 0) {
st->flags &= ~ST_FIXEDBLOCKS;
- else
+ } else {
st->flags |= ST_FIXEDBLOCKS;
+ }
st->blksiz = st->media_blksiz;
-#ifdef STDEBUG
- if(st_debug) printf("Used media_blksiz of %d\n",st->media_blksiz);
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("Used media_blksiz of %d\n", st->media_blksiz));
goto done;
}
-
- /***************************************************************\
- * We're getting no hints from any direction. Choose variable- *
- * length blocks arbitrarily. *
- \***************************************************************/
+ /*
+ * We're getting no hints from any direction. Choose variable-
+ * length blocks arbitrarily.
+ */
st->flags &= ~ST_FIXEDBLOCKS;
st->blksiz = 0;
-#ifdef STDEBUG
- if(st_debug) printf("Give up and default to variable mode\n");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3, ("Give up and default to variable mode\n"));
done:
- st->flags &= ~ST_AT_BOM;
- return (st_mode_select(unit, 0));
+
+ /*
+ * Decide whether or not to write two file marks to signify end-
+ * of-data. Make the decision as a function of density. If
+ * the decision is not to use a second file mark, the SCSI BLANK
+ * CHECK condition code will be recognized as end-of-data when
+ * first read.
+ * (I think this should be a by-product of fixed/variable..julian)
+ */
+ switch (st->density) {
+/* case 8 mm: What is the SCSI density code for 8 mm, anyway? */
+ case QIC_11:
+ case QIC_24:
+ case QIC_120:
+ case QIC_150:
+ case QIC_525:
+ case QIC_1320:
+ st->flags &= ~ST_2FM_AT_EOD;
+ break;
+ default:
+ st->flags |= ST_2FM_AT_EOD;
+ }
+ return 0;
}
-/*******************************************************\
-* trim the size of the transfer if needed, *
-* called by physio *
-* basically the smaller of our min and the scsi driver's*
-* minphys *
-\*******************************************************/
-void stminphys(bp)
-struct buf *bp;
+/*
+ * trim the size of the transfer if needed,
+ * called by physio
+ * basically the smaller of our min and the scsi driver's
+ * minphys
+ */
+void
+stminphys(bp)
+ struct buf *bp;
{
- (*(st_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp);
+ (*(st_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
}
-/*******************************************************\
-* Actually translate the requested transfer into *
-* one the physical driver can understand *
-* The transfer is described by a buf and will include *
-* only one physical transfer. *
-\*******************************************************/
-
-int ststrategy(bp)
-struct buf *bp;
+/*
+ * Actually translate the requested transfer into
+ * one the physical driver can understand
+ * The transfer is described by a buf and will include
+ * only one physical transfer.
+ */
+void
+ststrategy(bp)
+ struct buf *bp;
{
- struct buf **dp;
+ struct buf **dp;
unsigned char unit;
- unsigned int opri;
+ u_int32 opri;
struct st_data *st;
ststrats++;
unit = UNIT((bp->b_dev));
st = st_data[unit];
-#ifdef STDEBUG
- if(scsi_debug & PRINTROUTINES) printf("\nststrategy ");
- if(scsi_debug & SHOWREQUESTS) printf("st%d: %d bytes @ blk%d\n",
- unit,bp->b_bcount,bp->b_blkno);
-#endif /*STDEBUG*/
- /*******************************************************\
- * If it's a null transfer, return immediatly *
- \*******************************************************/
- if (bp->b_bcount == 0)
- {
+ SC_DEBUG(st->sc_link, SDEV_DB1,
+ (" strategy: %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno));
+ /*
+ * If it's a null transfer, return immediatly
+ */
+ if (bp->b_bcount == 0) {
goto done;
}
-
- /*******************************************************\
- * If we're at beginning of medium, now is the time to *
- * set medium access density, fixed or variable-blocks *
- * and, if fixed, the block size. *
- \*******************************************************/
- if (st->flags & ST_AT_BOM &&
- (bp->b_error = st_decide_mode(unit, (bp->b_flags & B_READ) != 0)))
- goto bad;
-
- /*******************************************************\
- * Odd sized request on fixed drives are verboten *
- \*******************************************************/
- if(st->flags & ST_FIXEDBLOCKS)
- {
- if(bp->b_bcount % st->blksiz)
- {
+ /*
+ * Odd sized request on fixed drives are verboten
+ */
+ if (st->flags & ST_FIXEDBLOCKS) {
+ if (bp->b_bcount % st->blksiz) {
printf("st%d: bad request, must be multiple of %d\n",
- unit, st->blksiz);
+ unit, st->blksiz);
bp->b_error = EIO;
goto bad;
}
}
- /*******************************************************\
- * as are out-of-range requests on variable drives. *
- \*******************************************************/
- else if(bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax)
- {
+ /*
+ * as are out-of-range requests on variable drives.
+ */
+ else if (bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax) {
printf("st%d: bad request, must be between %d and %d\n",
- unit, st->blkmin, st->blkmax);
+ unit, st->blkmin, st->blkmax);
bp->b_error = EIO;
goto bad;
}
-
stminphys(bp);
opri = splbio();
- /*******************************************************\
- * Place it in the queue of activities for this tape *
- * at the end (a bit silly because we only have on user..*
- * (but it could fork() )) *
- \*******************************************************/
+ /*
+ * Place it in the queue of activities for this tape
+ * at the end (a bit silly because we only have on user..
+ * (but it could fork() ))
+ */
dp = &(st->buf_queue);
- while (*dp)
- {
+ while (*dp) {
dp = &((*dp)->b_actf);
- }
+ }
*dp = bp;
bp->b_actf = NULL;
- /*******************************************************\
- * Tell the device to get going on the transfer if it's *
- * not doing anything, otherwise just wait for completion*
- * (All a bit silly if we're only allowing 1 open but..) *
- \*******************************************************/
+ /*
+ * Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion
+ * (All a bit silly if we're only allowing 1 open but..)
+ */
ststart(unit);
splx(opri);
@@ -928,1443 +935,993 @@ struct buf *bp;
bad:
bp->b_flags |= B_ERROR;
done:
- /*******************************************************\
- * Correctly set the buf to indicate a completed xfer *
- \*******************************************************/
+ /*
+ * Correctly set the buf to indicate a completed xfer
+ */
iodone(bp);
return;
}
+/*
+ * ststart looks to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It dequeues the buf and creates a scsi command to perform the
+ * transfer required. The transfer request will call scsi_done
+ * on completion, which will in turn call this routine again
+ * so that the next queued transfer is performed.
+ * The bufs are queued by the strategy routine (ststrategy)
+ *
+ * This routine is also called after other non-queued requests
+ * have been made of the scsi driver, to ensure that the queue
+ * continues to be drained.
+ * ststart() is called at splbio
+ */
+void
+ststart(unit)
+ u_int32 unit;
+{
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
+ register struct buf *bp = 0;
+ struct scsi_rw_tape cmd;
+ u_int32 flags;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("ststart "));
+ /*
+ * See if there is a buf to do and we are not already
+ * doing one
+ */
+ while (sc_link->opennings != 0) {
+
+ /* if a special awaits, let it proceed first */
+ if (sc_link->flags & SDEV_WAITING) {
+ wakeup((caddr_t)sc_link);
+ return;
+ }
+ if ((bp = st->buf_queue) == NULL) {
+ return; /* no work to bother with */
+ }
+ st->buf_queue = bp->b_actf;
+
+ /*
+ * if the device has been unmounted byt the user
+ * then throw away all requests until done
+ */
+ if ((!(st->flags & ST_MOUNTED))
+ || (!(sc_link->flags & SDEV_MEDIA_LOADED))) {
+ /* make sure that one implies the other.. */
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+ goto badnews;
+ }
+ /*
+ * only FIXEDBLOCK devices have pending operations
+ */
+ if (st->flags & ST_FIXEDBLOCKS) {
+ /*
+ * If we are at a filemark but have not reported it yet
+ * then we should report it now
+ */
+ if (st->flags & ST_AT_FILEMARK) {
+ if ((bp->b_flags & B_READ) == B_WRITE) {
+ /*
+ * Handling of ST_AT_FILEMARK in
+ * st_space will fill in the right file
+ * mark count.
+ * Back up over filemark
+ */
+ if (st_space(unit, 0, SP_FILEMARKS, 0) !=
+ ESUCCESS)
+ goto badnews;
+ } else {
+ bp->b_resid = bp->b_bcount;
+ bp->b_error = 0;
+ bp->b_flags &= ~B_ERROR;
+ st->flags &= ~ST_AT_FILEMARK;
+ biodone(bp);
+ continue; /* seek more work */
+ }
+ }
+ /*
+ * If we are at EIO (e.g. EOM) but have not reported it
+ * yet then we should report it now
+ */
+ if (st->flags & ST_EIO_PENDING) {
+ bp->b_resid = bp->b_bcount;
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ st->flags &= ~ST_EIO_PENDING;
+ biodone(bp);
+ continue; /* seek more work */
+ }
+ }
+ /*
+ * Fill out the scsi command
+ */
+ bzero(&cmd, sizeof(cmd));
+ if ((bp->b_flags & B_READ) == B_WRITE) {
+ cmd.op_code = WRITE_COMMAND_TAPE;
+ st->flags &= ~ST_FM_WRITTEN;
+ st->flags |= ST_WRITTEN;
+ flags = SCSI_DATA_OUT;
+ } else {
+ cmd.op_code = READ_COMMAND_TAPE;
+ flags = SCSI_DATA_IN;
+ }
+ /*
+ * Handle "fixed-block-mode" tape drives by using the
+ * block count instead of the length.
+ */
+ if (st->flags & ST_FIXEDBLOCKS) {
+ cmd.byte2 |= SRWT_FIXED;
+ lto3b(bp->b_bcount / st->blksiz, cmd.len);
+ } else {
+ lto3b(bp->b_bcount, cmd.len);
+ }
+ /*
+ * go ask the adapter to do all this for us
+ */
+ if (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &cmd,
+ sizeof(cmd),
+ (u_char *) bp->b_un.b_addr,
+ bp->b_bcount,
+ 0, /* can't retry a read on a tape really */
+ 100000,
+ bp,
+ flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) {
+ stqueues++;
+ } else {
+badnews:
+ printf("st%d: oops not queued\n", unit);
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ biodone(bp);
+ }
+ } /* go back and see if we can cram more work in.. */
+}
-
-/*******************************************************\
-* Perform special action on behalf of the user *
-* Knows about the internals of this device *
-\*******************************************************/
-stioctl(dev, cmd, arg, mode)
-dev_t dev;
-int cmd;
-caddr_t arg;
+/*
+ * Perform special action on behalf of the user;
+ * knows about the internals of this device
+ */
+errval
+stioctl(dev, cmd, arg, flag)
+ dev_t dev;
+ int cmd;
+ caddr_t arg;
+ int flag;
{
- int errcode = 0;
+ errval errcode = 0;
unsigned char unit;
- int number,flags,dsty;
- struct st_data *st;
-
-
- /*******************************************************\
- * Find the device that the user is talking about *
- \*******************************************************/
- flags = 0; /* give error messages, act on errors etc. */
+ u_int32 number, flags, dsty;
+ struct st_data *st;
+ u_int32 hold_blksiz;
+ u_int32 hold_density;
+ int32 nmarks;
+ struct mtop *mt = (struct mtop *) arg;
+
+ /*
+ * Find the device that the user is talking about
+ */
+ flags = 0; /* give error messages, act on errors etc. */
unit = UNIT(dev);
dsty = DSTY(dev);
- st = st_data[unit];
+ st = st_data[unit];
+ hold_blksiz = st->blksiz;
+ hold_density = st->density;
- switch(cmd)
- {
+ switch (cmd) {
case MTIOCGET:
- {
- struct mtget *g = (struct mtget *) arg;
-
- bzero(g, sizeof(struct mtget));
- g->mt_type = 0x7; /* Ultrix compat */ /*?*/
- if (st->flags & ST_FIXEDBLOCKS) {
- g->mt_bsiz = st->blksiz;
- } else {
- g->mt_bsiz = 0;
- }
- g->mt_dns_dflt = st->modes[0].density;
- g->mt_dns_dsty1 = st->modes[DSTY1].density;
- g->mt_dns_dsty2 = st->modes[DSTY2].density;
- g->mt_dns_dsty3 = st->modes[DSTY3].density;
- break;
- }
-
-
+ {
+ struct mtget *g = (struct mtget *) arg;
+
+ SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: get status]\n"));
+ bzero(g, sizeof(struct mtget));
+ g->mt_type = 0x7; /* Ultrix compat *//*? */
+ g->mt_density = st->density;
+ g->mt_blksiz = st->blksiz;
+ g->mt_density0 = st->modes[0].density;
+ g->mt_density1 = st->modes[1].density;
+ g->mt_density2 = st->modes[2].density;
+ g->mt_density3 = st->modes[3].density;
+ g->mt_blksiz0 = st->modes[0].blksiz;
+ g->mt_blksiz1 = st->modes[1].blksiz;
+ g->mt_blksiz2 = st->modes[2].blksiz;
+ g->mt_blksiz3 = st->modes[3].blksiz;
+ break;
+ }
case MTIOCTOP:
- {
- int nmarks;
- struct mtop *mt = (struct mtop *) arg;
-
-#ifdef STDEBUG
- if (st_debug)
- printf("[sctape_sstatus: %x %x]\n",
- mt->mt_op, mt->mt_count);
-#endif /*STDEBUG*/
-
+ {
+ SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: op=0x%x count=0x%x]\n",
+ mt->mt_op, mt->mt_count));
- /* compat: in U*x it is a short */
- number = mt->mt_count;
- switch ((short)(mt->mt_op))
- {
- case MTWEOF: /* write an end-of-file record */
- errcode = st_write_filemarks(unit,number,flags);
- break;
- case MTBSF: /* backward space file */
- number = -number;
- case MTFSF: /* forward space file */
- errcode = st_chkeod(unit, FALSE, &nmarks, flags);
- if (errcode == ESUCCESS)
- errcode = st_space(unit, number - nmarks,
- SP_FILEMARKS, flags);
- break;
- case MTBSR: /* backward space record */
- number = -number;
- case MTFSR: /* forward space record */
- errcode = st_chkeod(unit, TRUE, &nmarks, flags);
- if (errcode == ESUCCESS)
- errcode = st_space(unit,number,SP_BLKS,flags);
- break;
- case MTREW: /* rewind */
- errcode = st_rewind(unit,FALSE,flags);
- break;
- case MTOFFL: /* rewind and put the drive offline */
- if(st_rewind(unit,FALSE,flags))
- {
- printf("st%d: rewind failed, unit still loaded\n",
- unit);
- }
- else
- {
- st_prevent(unit,PR_ALLOW,0);
- st_load(unit,LD_UNLOAD,flags);
- }
- break;
- case MTNOP: /* no operation, sets status only */
- case MTCACHE: /* enable controller cache */
- case MTNOCACHE: /* disable controller cache */
- break;
- case MTSETBSIZ: /* Set block size for device */
- if (!(st->flags & ST_AT_BOM))
- {
- errcode = EINVAL;
+ /* compat: in U*x it is a short */
+ number = mt->mt_count;
+ switch ((short) (mt->mt_op)) {
+ case MTWEOF: /* write an end-of-file record */
+ errcode = st_write_filemarks(unit, number, flags);
break;
- }
- if (number == 0)
- {
- st->flags &= ~ST_FIXEDBLOCKS;
- }
- else
- {
- if ((st->blkmin || st->blkmax) /* they exist */
- && ((number < st->blkmin
- || number > st->blkmax)))
- {
+ case MTBSF: /* backward space file */
+ number = -number;
+ case MTFSF: /* forward space file */
+ errcode = st_chkeod(unit, FALSE, &nmarks, flags);
+ if (errcode == ESUCCESS)
+ errcode = st_space(unit, number - nmarks,
+ SP_FILEMARKS, flags);
+ break;
+ case MTBSR: /* backward space record */
+ number = -number;
+ case MTFSR: /* forward space record */
+ errcode = st_chkeod(unit, TRUE, &nmarks, flags);
+ if (errcode == ESUCCESS)
+ errcode = st_space(unit, number, SP_BLKS, flags);
+ break;
+ case MTREW: /* rewind */
+ errcode = st_rewind(unit, FALSE, flags);
+ break;
+ case MTOFFL: /* rewind and put the drive offline */
+ st_unmount(unit, EJECT);
+ break;
+ case MTNOP: /* no operation, sets status only */
+ case MTCACHE: /* enable controller cache */
+ case MTNOCACHE: /* disable controller cache */
+ break;
+ case MTSETBSIZ: /* Set block size for device */
+#ifdef NOTYET
+ if (!(st->flags & ST_NEW_MOUNT)) {
+ uprintf("re-mount tape before changing blocksize");
errcode = EINVAL;
break;
}
- st->flags |= ST_FIXEDBLOCKS;
- }
- st->blksiz = number;
- st->flags |= ST_BLOCK_SET;
- break;
+#endif
+ if (number == 0) {
+ st->flags &= ~ST_FIXEDBLOCKS;
+ } else {
+ if ((st->blkmin || st->blkmax) /* they exist */
+ &&((number < st->blkmin
+ || number > st->blkmax))) {
+ errcode = EINVAL;
+ break;
+ }
+ st->flags |= ST_FIXEDBLOCKS;
+ }
+ st->blksiz = number;
+ st->flags |= ST_BLOCK_SET; /*XXX */
+ goto try_new_value;
- /* How do we check that the drive can handle
- the requested density ? */
+ case MTSETDNSTY: /* Set density for device and mode */
+ if (number > SCSI_2_MAX_DENSITY_CODE) {
+ errcode = EINVAL;
+ } else {
+ st->density = number;
+ }
+ goto try_new_value;
- case MTSETDNSTY: /* Set density for device and mode */
- if (number < 0 || number > SCSI_2_MAX_DENSITY_CODE)
- {
+ default:
errcode = EINVAL;
}
- else
- {
- st->modes[dsty].density = number;
- }
break;
-
- default:
- errcode = EINVAL;
}
- break;
- }
case MTIOCIEOT:
case MTIOCEEOT:
break;
default:
- errcode = EINVAL;
+ if(MODE(dev) == CTLMODE)
+ errcode = scsi_do_ioctl(st->sc_link,cmd,arg,flag);
+ else
+ errcode = ENOTTY;
+ break;
}
-
return errcode;
+/*-----------------------------*/
+try_new_value:
+ /*
+ * Check that the mode being asked for is aggreeable to the
+ * drive. If not, put it back the way it was.
+ */
+ if (errcode = st_mode_select(unit, 0)) { /* put it back as it was */
+ printf("st%d: Cannot set selected mode", unit);
+ st->density = hold_density;
+ st->blksiz = hold_blksiz;
+ if (st->blksiz) {
+ st->flags |= ST_FIXEDBLOCKS;
+ } else {
+ st->flags &= ~ST_FIXEDBLOCKS;
+ }
+ return (errcode);
+ }
+ /*
+ * As the drive liked it, if we are setting a new default,
+ * set it into the structures as such.
+ *
+ * The means for deciding this are not finalised yet
+ */
+ if (MODE(dev) == 0x03) {
+ /* special mode */
+ /* XXX */
+ switch ((short) (mt->mt_op)) {
+ case MTSETBSIZ:
+ st->modes[dsty].blksiz = st->blksiz;
+ st->modeflags[dsty] |= BLKSIZE_SET_BY_USER;
+ break;
+ case MTSETDNSTY:
+ st->modes[dsty].density = st->density;
+ st->modeflags[dsty] |= DENSITY_SET_BY_USER;
+ break;
+ }
+ }
+ return 0;
}
-/*******************************************************\
-* Do a synchronous read. *
-\*******************************************************/
-int st_read(unit, buf, size, flags)
-int unit, size, flags;
-char *buf;
+/*
+ * Do a synchronous read.
+ */
+errval
+st_read(unit, buf, size, flags)
+ u_int32 unit, size, flags;
+ char *buf;
{
- int error;
struct scsi_rw_tape scsi_cmd;
struct st_data *st = st_data[unit];
- /*******************************************************\
- * If it's a null transfer, return immediatly *
- \*******************************************************/
- if (size == 0)
- {
- return(ESUCCESS);
+ /*
+ * If it's a null transfer, return immediatly
+ */
+ if (size == 0) {
+ return (ESUCCESS);
}
-
- /*******************************************************\
- * If we're at beginning of medium, now is the time to *
- * set medium access density, fixed or variable-blocks *
- * and, if fixed, the block size. *
- \*******************************************************/
- if (st->flags & ST_AT_BOM && (error = st_decide_mode(unit, TRUE)))
- return (error);
-
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = READ_COMMAND_TAPE;
- scsi_cmd.byte2 |= st->flags & ST_FIXEDBLOCKS ? SRWT_FIXED : 0;
- lto3b(scsi_cmd.byte2 & SRWT_FIXED ?
- size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE) : size,
- scsi_cmd.len);
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- buf,
- size,
- 100000,
- NULL,
- flags | SCSI_DATA_IN));
-}
-
-/*******************************************************\
-* Get scsi driver to send a "are you ready" command *
-\*******************************************************/
-st_test_ready(unit,flags)
-int unit,flags;
-{
- struct scsi_test_unit_ready scsi_cmd;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = TEST_UNIT_READY;
-
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 100000,
- NULL,
- flags));
+ if (st->flags & ST_FIXEDBLOCKS) {
+ scsi_cmd.byte2 |= SRWT_FIXED;
+ lto3b(size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE),
+ scsi_cmd.len);
+ } else {
+ lto3b(size, scsi_cmd.len);
+ }
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) buf,
+ size,
+ 0, /* not on io commands */
+ 100000,
+ NULL,
+ flags | SCSI_DATA_IN));
}
-
-
#ifdef __STDC__
#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
#else
#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 )
#endif
-/*******************************************************\
-* Ask the drive what it's min and max blk sizes are. *
-\*******************************************************/
+/*
+ * Ask the drive what it's min and max blk sizes are.
+ */
+errval
st_rd_blk_lim(unit, flags)
-int unit,flags;
+ u_int32 unit, flags;
{
- struct scsi_blk_limits scsi_cmd;
+ struct scsi_blk_limits scsi_cmd;
struct scsi_blk_limits_data scsi_blkl;
struct st_data *st = st_data[unit];
- int errno;
-
- /*******************************************************\
- * First check if we have it all loaded *
- \*******************************************************/
- if ((st->flags & ST_INFO_VALID)) return 0;
-
- /*******************************************************\
- * do a 'Read Block Limits' *
- \*******************************************************/
+ errval errno;
+ struct scsi_link *sc_link = st->sc_link;
+
+ /*
+ * First check if we have it all loaded
+ */
+ if ((sc_link->flags & SDEV_MEDIA_LOADED))
+ return 0;
+
+ /*
+ * do a 'Read Block Limits'
+ */
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = READ_BLK_LIMITS;
- /*******************************************************\
- * do the command, update the global values *
- \*******************************************************/
- if ( errno = st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- &scsi_blkl,
- sizeof(scsi_blkl),
- 5000,
- NULL,
- flags | SCSI_DATA_IN))
- {
+ /*
+ * do the command, update the global values
+ */
+ if (errno = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & scsi_blkl,
+ sizeof(scsi_blkl),
+ ST_RETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_IN)) {
return errno;
- }
+ }
st->blkmin = b2tol(scsi_blkl.min_length);
st->blkmax = _3btol(&scsi_blkl.max_length_2);
-#ifdef STDEBUG
- if (st_debug)
- {
- printf("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax);
- }
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax));
return 0;
}
-/*******************************************************\
-* Get the scsi driver to send a full inquiry to the *
-* device and use the results to fill out the global *
-* parameter structure. *
-* *
-* called from: *
-* attach *
-* open *
-* ioctl (to reset original blksize) *
-\*******************************************************/
+/*
+ * Get the scsi driver to send a full inquiry to the
+ * device and use the results to fill out the global
+ * parameter structure.
+ *
+ * called from:
+ * attach
+ * open
+ * ioctl (to reset original blksize)
+ */
+errval
st_mode_sense(unit, flags)
-int unit,flags;
+ u_int32 unit, flags;
{
- int scsi_sense_len;
- int errno;
- char *scsi_sense_ptr;
- struct scsi_mode_sense scsi_cmd;
- struct scsi_sense
- {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- }scsi_sense;
+ u_int32 scsi_sense_len;
+ errval errno;
+ char *scsi_sense_ptr;
+ struct scsi_mode_sense scsi_cmd;
+ struct scsi_sense {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ } scsi_sense;
+
+ struct scsi_sense_page_0 {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
+ /* Tandberg tape drives returns page 00
+ * with the sense data, whether or not
+ * you want it( ie the don't like you
+ * saying you want anything less!!!!!
+ * They also expect page 00
+ * back when you issue a mode select
+ */
+ } scsi_sense_page_0;
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
- struct scsi_sense_page_0
- {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
- /* Tandberg tape drives returns page 00 */
- /* with the sense data, whether or not */
- /* you want it( ie the don't like you */
- /* saying you want anything less!!!!! */
- /* They also expect page 00 */
- /* back when you issue a mode select */
- }scsi_sense_page_0;
- struct st_data *st = st_data[unit];
-
- /*******************************************************\
- * First check if we have it all loaded *
- \*******************************************************/
- if ((st->flags & ST_INFO_VALID)) return 0;
-
- /*******************************************************\
- * Define what sort of structure we're working with *
- \*******************************************************/
- if (st->quirks & ST_Q_NEEDS_PAGE_0)
- {
+ /*
+ * Define what sort of structure we're working with
+ */
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
scsi_sense_len = sizeof(scsi_sense_page_0);
scsi_sense_ptr = (char *) &scsi_sense_page_0;
- }
- else
- {
+ } else {
scsi_sense_len = sizeof(scsi_sense);
scsi_sense_ptr = (char *) &scsi_sense;
}
-
- /*******************************************************\
- * Set up a mode sense *
- \*******************************************************/
+ /*
+ * Set up a mode sense
+ */
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = MODE_SENSE;
scsi_cmd.length = scsi_sense_len;
- /*******************************************************\
- * do the command, but we don't need the results *
- * just print them for our interest's sake, if asked, *
- * or if we need it as a template for the mode select *
- * store it away. *
- \*******************************************************/
- if (errno = st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- scsi_sense_ptr,
- scsi_sense_len,
- 5000,
- NULL,
- flags | SCSI_DATA_IN) )
- {
+ /*
+ * do the command, but we don't need the results
+ * just print them for our interest's sake, if asked,
+ * or if we need it as a template for the mode select
+ * store it away.
+ */
+ if (errno = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) scsi_sense_ptr,
+ scsi_sense_len,
+ ST_RETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_IN)) {
return errno;
- }
- st->numblks = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks));
- st->media_blksiz = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen));
- st->media_density = ((struct scsi_sense *)scsi_sense_ptr)->blk_desc.density;
- if (((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec &
- SMH_DSP_WRITE_PROT)
+ }
+ st->numblks = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks);
+ st->media_blksiz = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen);
+ st->media_density = ((struct scsi_sense *) scsi_sense_ptr)->blk_desc.density;
+ if (((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec &
+ SMH_DSP_WRITE_PROT) {
st->flags |= ST_READONLY;
-#ifdef STDEBUG
- if (st_debug)
- {
- printf("st%d: density code 0x%x, %d-byte blocks, write-%s, ",
- unit, st->media_density, st->media_blksiz,
- st->flags & ST_READONLY ? "protected" : "enabled");
- printf("%sbuffered\n",
- ((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec
- & SMH_DSP_BUFF_MODE ? "" : "un");
}
-#endif /*STDEBUG*/
- if (st->quirks & ST_Q_NEEDS_PAGE_0)
- {
- bcopy(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data,
- st->sense_data,
- sizeof(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data));
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("density code 0x%x, %d-byte blocks, write-%s, ",
+ st->media_density, st->media_blksiz,
+ st->flags & ST_READONLY ? "protected" : "enabled"));
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("%sbuffered\n",
+ ((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec
+ & SMH_DSP_BUFF_MODE ? "" : "un"));
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
+ bcopy(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data,
+ st->sense_data,
+ sizeof(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data));
}
+ sc_link->flags |= SDEV_MEDIA_LOADED;
return 0;
}
-/*******************************************************\
-* Send a filled out parameter structure to the drive to *
-* set it into the desire modes etc. *
-\*******************************************************/
+/*
+ * Send a filled out parameter structure to the drive to
+ * set it into the desire modes etc.
+ */
+errval
st_mode_select(unit, flags)
-int unit, flags;
+ u_int32 unit, flags;
{
- int dat_len;
- char *dat_ptr;
+ u_int32 dat_len;
+ char *dat_ptr;
struct scsi_mode_select scsi_cmd;
- struct dat
- {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- }dat;
- struct dat_page_0
- {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
- }dat_page_0;
- struct st_data *st = st_data[unit];
-
- /*******************************************************\
- * Define what sort of structure we're working with *
- \*******************************************************/
- if (st->quirks & ST_Q_NEEDS_PAGE_0)
- {
+ struct dat {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ } dat;
+ struct dat_page_0 {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
+ } dat_page_0;
+ struct st_data *st = st_data[unit];
+
+ /*
+ * Define what sort of structure we're working with
+ */
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
dat_len = sizeof(dat_page_0);
dat_ptr = (char *) &dat_page_0;
- }
- else
- {
+ } else {
dat_len = sizeof(dat);
dat_ptr = (char *) &dat;
}
-
- /*******************************************************\
- * Set up for a mode select *
- \*******************************************************/
+ /*
+ * Set up for a mode select
+ */
bzero(dat_ptr, dat_len);
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = MODE_SELECT;
scsi_cmd.length = dat_len;
- ((struct dat *)dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc);
- ((struct dat *)dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
- ((struct dat *)dat_ptr)->blk_desc.density = st->density;
- if(st->flags & ST_FIXEDBLOCKS)
- {
- lto3b( st->blksiz , ((struct dat *)dat_ptr)->blk_desc.blklen);
+ ((struct dat *) dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc);
+ ((struct dat *) dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
+ ((struct dat *) dat_ptr)->blk_desc.density = st->density;
+ if (st->flags & ST_FIXEDBLOCKS) {
+ lto3b(st->blksiz, ((struct dat *) dat_ptr)->blk_desc.blklen);
}
- if (st->quirks & ST_Q_NEEDS_PAGE_0)
- {
- bcopy(st->sense_data, ((struct dat_page_0 *)dat_ptr)->sense_data,
- sizeof(((struct dat_page_0 *)dat_ptr)->sense_data));
- /* the Tandberg tapes need the block size to */
- /* be set on each mode sense/select. */
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
+ bcopy(st->sense_data, ((struct dat_page_0 *) dat_ptr)->sense_data,
+ sizeof(((struct dat_page_0 *) dat_ptr)->sense_data));
+ /* the Tandberg tapes need the block size to */
+ /* be set on each mode sense/select. */
}
- /*******************************************************\
- * do the command *
- \*******************************************************/
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- dat_ptr,
- dat_len,
- 5000,
- NULL,
- flags | SCSI_DATA_OUT) );
+ /*
+ * do the command
+ */
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) dat_ptr,
+ dat_len,
+ ST_RETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_OUT));
}
-/*******************************************************\
-* skip N blocks/filemarks/seq filemarks/eom *
-\*******************************************************/
-st_space(unit,number,what,flags)
-int unit,number,what,flags;
+/*
+ * skip N blocks/filemarks/seq filemarks/eom
+ */
+errval
+st_space(unit, number, what, flags)
+ u_int32 unit, what, flags;
+ int32 number;
{
- int error;
+ errval error;
struct scsi_space scsi_cmd;
- struct st_data *st = st_data[unit];
-
- /*******************************************************\
- * If we're at beginning of medium, now is the time to *
- * set medium access density, fixed or variable-blocks *
- * and, if fixed, the block size. *
- \*******************************************************/
- if (st->flags & ST_AT_BOM &&
- (error = st_decide_mode(unit, TRUE)))
- return (error);
+ struct st_data *st = st_data[unit];
- switch (what)
- {
- case SP_BLKS:
- if (st->flags & ST_PER_ACTION)
- {
- if (number > 0)
- {
+ switch (what) {
+ case SP_BLKS:
+ if (st->flags & ST_PER_ACTION) {
+ if (number > 0) {
st->flags &= ~ST_PER_ACTION;
- return(EIO);
- }
- else if (number < 0)
- {
- if (st->flags & ST_AT_FILEMARK)
- {
- /*******************************\
- * Handling of ST_AT_FILEMARK *
- * in st_space will fill in the *
- * right file mark count. *
- \*******************************/
+ return (EIO);
+ } else if (number < 0) {
+ if (st->flags & ST_AT_FILEMARK) {
+ /*
+ * Handling of ST_AT_FILEMARK
+ * in st_space will fill in the
+ * right file mark count.
+ */
error = st_space(unit, 0, SP_FILEMARKS,
flags);
- if (error) return(error);
+ if (error)
+ return (error);
}
- if (st->flags & ST_BLANK_READ)
- {
+ if (st->flags & ST_BLANK_READ) {
st->flags &= ~ST_BLANK_READ;
- return(EIO);
+ return (EIO);
}
st->flags &= ~ST_EIO_PENDING;
}
}
break;
- case SP_FILEMARKS:
- if (st->flags & ST_EIO_PENDING)
- {
- if (number > 0)
- {
+ case SP_FILEMARKS:
+ if (st->flags & ST_EIO_PENDING) {
+ if (number > 0) { /* pretend we just discover the error */
st->flags &= ~ST_EIO_PENDING;
- return(EIO);
- }
- else if (number < 0)
+ return (EIO);
+ } else if (number < 0) { /* back away from the error */
st->flags &= ~ST_EIO_PENDING;
+ }
}
- if (st->flags & ST_AT_FILEMARK)
- {
+ if (st->flags & ST_AT_FILEMARK) {
st->flags &= ~ST_AT_FILEMARK;
number--;
}
- if (st->flags & ST_BLANK_READ && number < 0)
- {
+ if ((st->flags & ST_BLANK_READ) && (number < 0)) { /* back away from unwritten tape */
st->flags &= ~ST_BLANK_READ;
- number++;
+ number++; /* dubious */
}
}
- if (number == 0)
- return(ESUCCESS);
+ if (number == 0) {
+ return (ESUCCESS);
+ }
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = SPACE;
scsi_cmd.byte2 = what & SS_CODE;
- lto3b(number,scsi_cmd.number);
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 600000, /* 10 mins enough? */
- NULL,
- flags));
+ lto3b(number, scsi_cmd.number);
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 0, /* no retries please , just fail */
+ 600000, /* 10 mins enough? */
+ NULL,
+ flags));
}
-/*******************************************************\
-* write N filemarks *
-\*******************************************************/
-st_write_filemarks(unit,number,flags)
-int unit,number,flags;
+
+/*
+ * write N filemarks
+ */
+errval
+st_write_filemarks(unit, number, flags)
+ u_int32 unit, flags;
+ int32 number;
{
- int error;
struct scsi_write_filemarks scsi_cmd;
- struct st_data *st = st_data[unit];
-
- /*******************************************************\
- * It's hard to write a negative number of file marks. *
- * Don't try. *
- \*******************************************************/
- if (number < 0)
- return (EINVAL);
-
- /*******************************************************\
- * If we're at beginning of medium, now is the time to *
- * set medium access density, fixed or variable-blocks *
- * and, if fixed, the block size. *
- \*******************************************************/
- if (st->flags & ST_AT_BOM && number > 0 &&
- (error = st_decide_mode(unit, FALSE)))
- return (error);
+ struct st_data *st = st_data[unit];
- switch (number)
- {
- case 0: /* really a command to sync the drive's buffers */
+ /*
+ * It's hard to write a negative number of file marks.
+ * Don't try.
+ */
+ if (number < 0) {
+ return EINVAL;
+ }
+ switch (number) {
+ case 0: /* really a command to sync the drive's buffers */
break;
- case 1:
- if (st->flags & ST_FM_WRITTEN)
+ case 1:
+ if (st->flags & ST_FM_WRITTEN) { /* already have one down */
st->flags &= ~ST_WRITTEN;
- else
+ } else {
st->flags |= ST_FM_WRITTEN;
+ }
st->flags &= ~ST_PER_ACTION;
break;
default:
st->flags &= ~(ST_PER_ACTION | ST_WRITTEN);
}
-
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = WRITE_FILEMARKS;
- lto3b(number,scsi_cmd.number);
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 100000, /* 10 secs.. (may need to repos head )*/
- NULL,
- flags) );
+ lto3b(number, scsi_cmd.number);
+ return scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 0, /* no retries, just fail */
+ 100000, /* 10 secs.. (may need to repos head ) */
+ NULL,
+ flags);
}
-/***************************************************************\
-* Make sure the right number of file marks is on tape if the *
-* tape has been written. If the position argument is true, *
-* leave the tape positioned where it was originally. *
-* *
-* nmarks returns the number of marks to skip (or, if position *
-* true, which were skipped) to get back original position. *
-\***************************************************************/
+/*
+ * Make sure the right number of file marks is on tape if the
+ * tape has been written. If the position argument is true,
+ * leave the tape positioned where it was originally.
+ *
+ * nmarks returns the number of marks to skip (or, if position
+ * true, which were skipped) to get back original position.
+ */
+int32
st_chkeod(unit, position, nmarks, flags)
-int unit;
-int position;
-int *nmarks;
-int flags;
+ u_int32 unit;
+ boolean position;
+ int32 *nmarks;
+ u_int32 flags;
{
- int error;
- struct st_data *st = st_data[unit];
+ errval error;
+ struct st_data *st = st_data[unit];
- switch (st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD))
- {
+ switch (st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD)) {
default:
*nmarks = 0;
- return(ESUCCESS);
- case ST_WRITTEN:
- case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD:
+ return (ESUCCESS);
+ case ST_WRITTEN:
+ case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD:
*nmarks = 1;
break;
- case ST_WRITTEN | ST_2FM_AT_EOD:
+ case ST_WRITTEN | ST_2FM_AT_EOD:
*nmarks = 2;
}
error = st_write_filemarks(unit, *nmarks, flags);
- if (position && error == ESUCCESS)
+ if (position && (error == ESUCCESS))
error = st_space(unit, -*nmarks, SP_FILEMARKS, flags);
return (error);
}
-/*******************************************************\
-* load/unload (with retension if true) *
-\*******************************************************/
-st_load(unit,type,flags)
-int unit,type,flags;
+/*
+ * load/unload (with retension if true)
+ */
+errval
+st_load(unit, type, flags)
+ u_int32 unit, type, flags;
{
- struct scsi_load scsi_cmd;
- struct st_data *st = st_data[unit];
+ struct scsi_load scsi_cmd;
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
- st->flags &= ~ST_PER_MEDIA;
bzero(&scsi_cmd, sizeof(scsi_cmd));
- if (type == LD_LOAD)
- {
- /*scsi_cmd.how |= LD_RETEN;*/
- st->flags |= ST_AT_BOM;
- }
- else
- {
- int error, nmarks;
+ if (type != LD_LOAD) {
+ errval error;
+ int32 nmarks;
error = st_chkeod(unit, FALSE, &nmarks, flags);
- if (error != ESUCCESS) return(error);
- st->flags &= ~ST_INFO_VALID;
+ if (error != ESUCCESS)
+ return (error);
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
}
- if(st->quirks & ST_Q_IGNORE_LOADS) return(0);
+ if (st->quirks & ST_Q_IGNORE_LOADS)
+ return (0);
scsi_cmd.op_code = LOAD_UNLOAD;
scsi_cmd.how |= type;
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 300000, /* 5 min */
- NULL,
- flags));
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ ST_RETRIES,
+ 300000, /* 5 min */
+ NULL,
+ flags));
}
-/*******************************************************\
-* Prevent or allow the user to remove the tape *
-\*******************************************************/
-st_prevent(unit,type,flags)
-int unit,type,flags;
-{
- struct scsi_prevent scsi_cmd;
- if (type == PR_ALLOW)
- {
- int error, nmarks;
-
- error = st_chkeod(unit, TRUE, &nmarks, flags);
- if (error != ESUCCESS) return(error);
- st_data[unit]->flags &= ~ST_INFO_VALID;
- }
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = PREVENT_ALLOW;
- scsi_cmd.how=type;
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 5000,
- NULL,
- flags));
-}
-/*******************************************************\
-* Rewind the device *
-\*******************************************************/
-st_rewind(unit,immed,flags)
-int unit,immed,flags;
+/*
+ * Rewind the device
+ */
+errval
+st_rewind(unit, immed, flags)
+ u_int32 unit, flags;
+ boolean immed;
{
- struct scsi_rewind scsi_cmd;
- struct st_data *st = st_data[unit];
- int error, nmarks;
+ struct scsi_rewind scsi_cmd;
+ struct st_data *st = st_data[unit];
+ errval error;
+ int32 nmarks;
error = st_chkeod(unit, FALSE, &nmarks, flags);
- if (error != ESUCCESS) return(error);
+ if (error != ESUCCESS)
+ return (error);
st->flags &= ~ST_PER_ACTION;
- st->flags |= ST_AT_BOM;
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = REWIND;
scsi_cmd.byte2 = immed ? SR_IMMED : 0;
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- immed?5000:300000, /* 5 sec or 5 min */
- NULL,
- flags));
-}
-
-/***************************************************************\
-* ststart looks to see if there is a buf waiting for the device *
-* and that the device is not already busy. If both are true, *
-* It deques the buf and creates a scsi command to perform the *
-* transfer in the buf. The transfer request will call st_done *
-* on completion, which will in turn call this routine again *
-* so that the next queued transfer is performed. *
-* The bufs are queued by the strategy routine (ststrategy) *
-* *
-* This routine is also called after other non-queued requests *
-* have been made of the scsi driver, to ensure that the queue *
-* continues to be drained. *
-\***************************************************************/
-/* ststart() is called at splbio */
-ststart(unit)
-{
- int drivecount;
- register struct buf *bp = 0;
- register struct buf *dp;
- struct scsi_rw_tape cmd;
- int blkno, nblk;
- struct st_data *st = st_data[unit];
- int flags;
-
-
-
-#ifdef STDEBUG
- if(scsi_debug & PRINTROUTINES) printf("ststart%d ",unit);
-#endif /*STDEBUG*/
- /*******************************************************\
- * See if there is a buf to do and we are not already *
- * doing one *
- \*******************************************************/
- if(st->scsi_xfer.flags & INUSE)
- {
- return; /* unit already underway */
- }
-trynext:
- if(st->xfer_block_wait) /* a special awaits, let it proceed first */
- {
- wakeup(&(st->xfer_block_wait));
- return;
- }
-
- if ((bp = st->buf_queue) == NULL)
- {
- return; /* no work to bother with */
- }
- st->buf_queue = bp->b_actf;
-
-
-
- /*******************************************************\
- * only FIXEDBLOCK devices have pending operations *
- \*******************************************************/
- if(st->flags & ST_FIXEDBLOCKS)
- {
- /*******************************************************\
- * If we are at a filemark but have not reported it yet *
- * then we should report it now *
- \*******************************************************/
- if(st->flags & ST_AT_FILEMARK)
- {
- if ((bp->b_flags & B_READ) == B_WRITE)
- {
- /***************************************\
- * Handling of ST_AT_FILEMARK in *
- * st_space will fill in the right file *
- * mark count. *
- \***************************************/
- if (st_space(unit, 0, SP_FILEMARKS, 0) !=
- ESUCCESS) goto badnews;
- }
- else
- {
- bp->b_resid = bp->b_bcount;
- bp->b_error = 0;
- bp->b_flags &= ~B_ERROR;
- st->flags &= ~ST_AT_FILEMARK;
- biodone(bp);
- goto trynext;
- }
- }
- /*******************************************************\
- * If we are at EIO (e.g. EOM) but have not reported it *
- * yet then we should report it now *
- \*******************************************************/
- if(st->flags & ST_EIO_PENDING)
- {
- bp->b_resid = bp->b_bcount;
- bp->b_error = EIO;
- bp->b_flags |= B_ERROR;
- st->flags &= ~ST_EIO_PENDING;
- biodone(bp);
- goto trynext;
- }
- }
- /*******************************************************\
- * Fill out the scsi command *
- \*******************************************************/
- bzero(&cmd, sizeof(cmd));
- if((bp->b_flags & B_READ) == B_WRITE)
- {
- cmd.op_code = WRITE_COMMAND_TAPE;
- st->flags &= ~ST_FM_WRITTEN;
- st->flags |= ST_WRITTEN;
- flags = SCSI_DATA_OUT;
- }
- else
- {
- cmd.op_code = READ_COMMAND_TAPE;
- flags = SCSI_DATA_IN;
- }
-
- /*******************************************************\
- * Handle "fixed-block-mode" tape drives by using the *
- * block count instead of the length. *
- \*******************************************************/
- if(st->flags & ST_FIXEDBLOCKS)
- {
- cmd.byte2 |= SRWT_FIXED;
- lto3b(bp->b_bcount/st->blksiz,cmd.len);
- }
- else
- {
- lto3b(bp->b_bcount,cmd.len);
- }
-
- /*******************************************************\
- * go ask the adapter to do all this for us *
- \*******************************************************/
- if (st_scsi_cmd(unit,
- &cmd,
- sizeof(cmd),
- (u_char *)bp->b_un.b_addr,
- bp->b_bcount,
- 100000,
- bp,
- flags | SCSI_NOSLEEP ) != SUCCESSFULLY_QUEUED)
-
- {
-badnews:
- printf("st%d: oops not queued\n",unit);
- bp->b_flags |= B_ERROR;
- bp->b_error = EIO;
- biodone(bp);
- return;
- }
- stqueues++;
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ ST_RETRIES,
+ immed ? 5000 : 300000, /* 5 sec or 5 min */
+ NULL,
+ flags));
}
-/*******************************************************\
-* This routine is called by the scsi interrupt when *
-* the transfer is complete.
-\*******************************************************/
-int st_done(unit,xs)
-int unit;
-struct scsi_xfer *xs;
-{
- struct buf *bp;
- int retval;
- struct st_data *st = st_data[unit];
-
-#ifdef STDEBUG
- if(scsi_debug & PRINTROUTINES) printf("st_done%d ",unit);
-#endif /*STDEBUG*/
-#ifdef PARANOID
- if (! (xs->flags & INUSE))
- panic("scsi_xfer not in use!");
-#endif /*PARANOID*/
- if((bp = xs->bp)== NULL)
- {
- wakeup(xs);
- return;
- }
- switch(xs->error)
- {
- case XS_NOERROR:
- bp->b_flags &= ~B_ERROR;
- bp->b_error = 0;
- bp->b_resid = 0;
- break;
- case XS_SENSE:
- retval = (st_interpret_sense(unit,xs));
- bp->b_resid = xs->resid; /* already multiplied by blksiz */
- if(retval)
- {
- /***************************************\
- * We have a real error, the bit should *
- * be set to indicate this. The return *
- * value will contain the unix error code*
- * that the error interpretation routine *
- * thought was suitable, so pass this *
- * value back in the buf structure. *
- * Furthermore we return information *
- * saying that no data was transferred *
- * All status is now suspect *
- \***************************************/
- bp->b_flags |= B_ERROR;
- bp->b_error = retval;
- bp->b_resid = bp->b_bcount;
- st->flags &= ~ST_PER_ACTION;
- }
- else
- {
- /***********************************************\
- * The error interpretation code has declared *
- * that it wasn't a real error, or at least that *
- * we should be ignoring it if it was. *
- \***********************************************/
- if(xs->resid == 0)
- {
- /***************************************\
- * we apparently had a corrected error *
- * or something. *
- * pretend the error never happenned *
- \***************************************/
- bp->b_flags &= ~B_ERROR;
- bp->b_error = 0;
- break;
- }
- if ( xs->resid != xs->datalen )
- {
- /***************************************\
- * Here we have the tricky part.. *
- * We successfully read less data than *
- * we requested. (but not 0) *
- *------for variable blocksize tapes:----*
- * UNDER 386BSD: *
- * We should legitimatly have the error *
- * bit set, with the error value set to *
- * zero.. This is to indicate to the *
- * physio code that while we didn't get *
- * as much information as was requested, *
- * we did reach the end of the record *
- * and so physio should not call us *
- * again for more data... we have it all *
- * SO SET THE ERROR BIT! *
- * *
- * UNDER NetBSD: *
- * To indicate the same as above, we *
- * need only have a non 0 resid that is *
- * less than the b_bcount, but the *
- * ERROR BIT MUST BE CLEAR! (sigh) *
- * *
- *-------for fixed blocksize device------*
- * We read some successful records *
- * before hitting the EOF or EOT. These *
- * must be passed to the user, before we *
- * report the EOx. We will report the *
- * EOx NEXT time. *
- \***************************************/
-#ifdef NETBSD
- bp->b_flags &= ~B_ERROR;
+#ifdef NETBSD
+#define SIGNAL_SHORT_READ
#else
- bp->b_flags |= B_ERROR;
-#endif
- bp->b_error = 0;
- xs->error = XS_NOERROR;
- break;
- }
- else
- {
- /***************************************\
- * We have come out of the error handler *
- * with no error code. We have also not *
- * transferred any data (would have gone *
- * to the previous clause). *
- * This must be an EOF *
- * Any caller request to read no *
- * data would have been short-circuited *
- * at st_read or ststrategy. *
- * *
- * At least all o/s agree that: *
- * 0 bytes read with no error is EOF *
- \***************************************/
-
- bp->b_error = 0;
- bp->b_flags &= ~B_ERROR;
- st->flags &= ~ST_AT_FILEMARK;
- break;
- }
- }
- break;
-
- case XS_TIMEOUT:
- printf("st%d: timeout\n",unit);
-
- case XS_BUSY: /* should retry */ /* how? */
- /************************************************/
- /* SHOULD put buf back at head of queue */
- /* and decrement retry count in (*xs) */
- /* HOWEVER, this should work as a kludge */
- /************************************************/
- if(xs->retries--)
- {
- xs->flags &= ~ITSDONE;
- xs->error = XS_NOERROR;
- if ( (*(st->sc_sw->scsi_cmd))(xs)
- == SUCCESSFULLY_QUEUED)
- { /* don't wake the job, ok? */
- return;
- }
- printf("st%d: device busy\n",unit);
- xs->flags |= ITSDONE;
- }
-
- case XS_DRIVER_STUFFUP:
- bp->b_flags |= B_ERROR;
- bp->b_error = EIO;
- break;
- default:
- printf("st%d: unknown error category from scsi driver\n"
- ,unit);
- }
- biodone(bp);
- xs->flags = 0; /* no longer in use */
- ststart(unit); /* If there's another waiting.. do it */
-}
-
-
+#define SIGNAL_SHORT_READ bp->b_flags |= B_ERROR;
+#endif
-/*******************************************************\
-* ask the scsi driver to perform a command for us. *
-* Call it through the switch table, and tell it which *
-* sub-unit we want, and what target and lu we wish to *
-* talk to. Also tell it where to find the command *
-* how long int is. *
-* Also tell it where to read/write the data, and how *
-* long the data is supposed to be *
-\*******************************************************/
-int st_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags)
-
-int unit,flags;
-struct scsi_generic *scsi_cmd;
-int cmdlen;
-int timeout;
-u_char *data_addr;
-struct buf *bp;
-int datalen;
+/*
+ * Look at the returned sense and act on the error and detirmine
+ * The unix error number to pass back... (0 = report no error)
+ * (-1 = continue processing)
+ */
+errval
+st_interpret_sense(xs)
+ struct scsi_xfer *xs;
{
- struct scsi_xfer *xs;
- int retval;
- int s;
- struct st_data *st = st_data[unit];
-
-#ifdef STDEBUG
- if(scsi_debug & PRINTROUTINES) printf("\nst_scsi_cmd%d ",unit);
-#endif /*STDEBUG*/
-#ifdef PARANOID
- if(st->sc_sw == NULL) /* If we have no scsi driver */
- {
- printf("st%d: not set up\n",unit);
- return(EINVAL);
+ struct scsi_link *sc_link = xs->sc_link;
+ struct scsi_sense_data *sense = &(xs->sense);
+ boolean silent = xs->flags & SCSI_SILENT;
+ struct buf *bp = xs->bp;
+ u_int32 unit = sc_link->dev_unit;
+ struct st_data *st = st_data[unit];
+ u_int32 key;
+ int32 info;
+
+ /*
+ * Get the sense fields and work out what code
+ */
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ info = ntohl(*((int32 *) sense->ext.extended.info));
+ } else {
+ info = xs->datalen; /* bad choice if fixed blocks */
}
-#endif /*PARANOID*/
-
- xs = &(st->scsi_xfer);
- if(!(flags & SCSI_NOMASK))
- s = splbio();
- st->xfer_block_wait++; /* there is someone waiting */
- while (xs->flags & INUSE)
- {
- if(flags & SCSI_NOSLEEP)
- return EBUSY;
- sleep(&(st->xfer_block_wait),PRIBIO+1);
+ if ((sense->error_code & SSD_ERRCODE) != 0x70) {
+ return (-1); /* let the generic code handle it */
}
- st->xfer_block_wait--;
- xs->flags = INUSE;
- if(!(flags & SCSI_NOMASK))
- splx(s);
-
- /*******************************************************\
- * Fill out the scsi_xfer structure *
- \*******************************************************/
- xs->flags |= flags;
- xs->adapter = st->ctlr;
- xs->targ = st->targ;
- xs->lu = st->lu;
- xs->retries = bp?0:ST_RETRIES;/*can't retry on IO*/
- xs->timeout = timeout;
- xs->cmd = scsi_cmd;
- xs->cmdlen = cmdlen;
- xs->data = data_addr;
- xs->datalen = datalen;
- xs->resid = datalen;
- xs->when_done = st_done;
- xs->done_arg = unit;
- xs->done_arg2 = (int)xs;
- xs->bp = bp;
-retry: xs->error = XS_NOERROR;
-
- /***********************************************\
- * Ask the adapter to do the command for us *
- \***********************************************/
- retval = (*(st->sc_sw->scsi_cmd))(xs);
-
- /***********************************************\
- * IO operations are handled differently.. *
- * Physio does the sleep, and error handling is *
- * Done in st_done at interrupt time *
- \***********************************************/
- if(bp) return retval;
-
- /***********************************************\
- * Wait for the result if queued, or handle the *
- * error if it was rejected.. *
- \***********************************************/
- switch(retval)
- {
- case SUCCESSFULLY_QUEUED:
- s = splbio();
- while(!(xs->flags & ITSDONE))
- sleep(xs,PRIBIO+1);
- splx(s);
- /*******************************\
- * finished.. check for failure *
- * Fall through...... *
- \*******************************/
- case HAD_ERROR:
- case COMPLETE:
- switch(xs->error)
- {
- case XS_NOERROR:
- retval = ESUCCESS;
- break;
- case XS_SENSE:
- retval = (st_interpret_sense(unit,xs));
- /* only useful for reads *//* why did I say that?*/
- if (retval)
- { /* error... don't care about filemarks */
- st->flags &= ~ST_PER_ACTION;
- }
- else
- {
- xs->error = XS_NOERROR;
- retval = ESUCCESS;
- }
- break;
- case XS_DRIVER_STUFFUP:
- retval = EIO;
- break;
- case XS_BUSY:
- /* should sleep 1 sec here */
- case XS_TIMEOUT:
- if(xs->retries-- )
- {
- xs->flags &= ~ITSDONE;
- goto retry;
+ if (st->flags & ST_FIXEDBLOCKS) {
+ xs->resid = info * st->blksiz;
+ if (sense->ext.extended.flags & SSD_EOM) {
+ st->flags |= ST_EIO_PENDING;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
}
- retval = EIO;
- break;
- default:
- retval = EIO;
- printf("st%d: unknown error category from scsi driver\n"
- ,unit);
- break;
- }
- break;
- case TRY_AGAIN_LATER:
- if(xs->retries-- )
- {
- xs->flags &= ~ITSDONE;
- /* should delay here */
- goto retry;
}
- retval = EIO;
- break;
- default:
- retval = EIO;
- }
- xs->flags = 0; /* it's free! */
- ststart(unit);
- return(retval);
-}
-/***************************************************************\
-* Look at the returned sense and act on the error and detirmine *
-* The unix error number to pass back... (0 = report no error) *
-\***************************************************************/
-
-int st_interpret_sense(unit,xs)
-int unit;
-struct scsi_xfer *xs;
-{
- struct scsi_sense_data *sense;
- int key;
- int silent = xs->flags & SCSI_SILENT;
- struct st_data *st = st_data[unit];
- int info;
- static char *error_mes[] = { "soft error (corrected)",
- "not ready", "medium error",
- "non-media hardware failure", "illegal request",
- "unit attention", "tape is write-protected",
- "no data found", "vendor unique",
- "copy aborted", "command aborted",
- "search returned equal", "volume overflow",
- "verify miscompare", "unknown error key"
- };
-
- /***************************************************************\
- * If errors are ok, report a success *
- \***************************************************************/
- if(xs->flags & SCSI_ERR_OK) return(ESUCCESS);
-
- /***************************************************************\
- * Get the sense fields and work out what code *
- \***************************************************************/
- sense = &(xs->sense);
-#ifdef STDEBUG
- if(st_debug)
- {
- int count = 0;
- printf("code%x valid%x\n"
- ,sense->error_code & SSD_ERRCODE
- ,sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
- printf("seg%x key%x ili%x eom%x fmark%x\n"
- ,sense->ext.extended.segment
- ,sense->ext.extended.flags & SSD_KEY
- ,sense->ext.extended.flags & SSD_ILI ? 1 : 0
- ,sense->ext.extended.flags & SSD_EOM ? 1 : 0
- ,sense->ext.extended.flags & SSD_FILEMARK ? 1 : 0);
- printf("info: %x %x %x %x followed by %d extra bytes\n"
- ,sense->ext.extended.info[0]
- ,sense->ext.extended.info[1]
- ,sense->ext.extended.info[2]
- ,sense->ext.extended.info[3]
- ,sense->ext.extended.extra_len);
- printf("extra: ");
- while(count < sense->ext.extended.extra_len)
- {
- printf ("%x ",sense->ext.extended.extra_bytes[count++]);
+ if (sense->ext.extended.flags & SSD_FILEMARK) {
+ st->flags |= ST_AT_FILEMARK;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
+ }
}
- printf("\n");
- }
-#endif /*STDEBUG*/
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- info = ntohl(*((long *)sense->ext.extended.info));
- }
- else
- {
- info = xs->datalen; /* bad choice if fixed blocks */
- }
-
-
- switch(sense->error_code & SSD_ERRCODE)
- {
- /***************************************************************\
- * If it's code 70, use the extended stuff and interpret the key *
- \***************************************************************/
- case 0x70:
- if(st->flags & ST_FIXEDBLOCKS)
- {
- xs->resid = info * st->blksiz;
- if(sense->ext.extended.flags & SSD_EOM)
- {
- st->flags |= ST_EIO_PENDING;
+ if (sense->ext.extended.flags & SSD_ILI) {
+ st->flags |= ST_EIO_PENDING;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
}
- if(sense->ext.extended.flags & SSD_FILEMARK)
- {
- st->flags |= ST_AT_FILEMARK;
+ if (sense->error_code & SSD_ERRCODE_VALID &&
+ !silent)
+ printf("st%d: block wrong size"
+ ", %d blocks residual\n", unit
+ ,info);
+
+ /*
+ * This quirk code helps the drive read
+ * the first tape block, regardless of
+ * format. That is required for these
+ * drives to return proper MODE SENSE
+ * information.
+ */
+ if ((st->quirks & ST_Q_SNS_HLP) &&
+ !(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ st->blksiz -= 512;
}
- if(sense->ext.extended.flags & SSD_ILI)
- {
- st->flags |= ST_EIO_PENDING;
- if (sense->error_code & SSD_ERRCODE_VALID &&
- !silent)
- printf("st%d: %d-byte block wrong size"
- "\n", unit, xs->datalen - info);
-
- /***************************************\
- * This quirk code helps the drive read *
- * the first tape block, regardless of *
- * format. That is required for these *
- * drives to return proper MODE SENSE *
- * information. *
- \***************************************/
- if ((st->quirks & ST_Q_SNS_HLP) &&
- !(st->flags & ST_INFO_VALID))
- {
- st->blksiz -= 512;
- }
+ }
+ /*
+ * If no data was tranfered, do it immediatly
+ */
+ if (xs->resid >= xs->datalen) {
+ if (st->flags & ST_EIO_PENDING) {
+ return EIO;
}
- /***********************************************\
- * If no data was tranfered, do it immediatly *
- \***********************************************/
- if(xs->resid >= xs->datalen)
- {
- if(st->flags & ST_EIO_PENDING)
- {
- return EIO;
- }
- if(st->flags & ST_AT_FILEMARK)
- {
- return 0;
+ if (st->flags & ST_AT_FILEMARK) {
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
}
+ return 0;
}
}
- else
- {
- xs->resid = xs->datalen; /* to be sure */
- if(sense->ext.extended.flags & SSD_EOM)
- {
- return(EIO);
+ } else { /* must be variable mode */
+ xs->resid = xs->datalen; /* to be sure */
+ if (sense->ext.extended.flags & SSD_EOM) {
+ return (EIO);
+ }
+ if (sense->ext.extended.flags & SSD_FILEMARK) {
+ if (bp)
+ bp->b_resid = bp->b_bcount;
+ return 0;
+ }
+ if (sense->ext.extended.flags & SSD_ILI) {
+ if (info < 0) {
+ /*
+ * the record was bigger than the read
+ */
+ if (!silent)
+ printf("st%d: %d-byte record "
+ "too big\n", unit,
+ xs->datalen - info);
+ return (EIO);
}
- if(sense->ext.extended.flags & SSD_FILEMARK)
- {
- return 0;
+ xs->resid = info;
+ if (bp) {
+ bp->b_resid = info;
+ SIGNAL_SHORT_READ
}
- if(sense->ext.extended.flags & SSD_ILI)
- {
- if(info < 0)
- /***************************************\
- * the record was bigger than the read *
- \***************************************/
- {
- if (!silent)
- printf("st%d: %d-byte record "
- "too big\n", unit,
- xs->datalen - info);
- return(EIO);
- }
- xs->resid = info;
+ }
+ }
+ key = sense->ext.extended.flags & SSD_KEY;
+
+ if (key == 0x8) {
+ /*
+ * This quirk code helps the drive read the
+ * first tape block, regardless of format. That
+ * is required for these drives to return proper
+ * MODE SENSE information.
+ */
+ if ((st->quirks & ST_Q_SNS_HLP) &&
+ !(sc_link->flags & SDEV_MEDIA_LOADED)) { /* still starting */
+ st->blksiz -= 512;
+ } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) {
+ st->flags |= ST_BLANK_READ;
+ xs->resid = xs->datalen;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ /*return an EOF */
}
- }/* there may be some other error. check the rest */
+ return (ESUCCESS);
+ }
+ }
+ return (-1); /* let the default/generic handler handle it */
+}
- key=sense->ext.extended.flags & SSD_KEY;
+/*
+ * The quirk here is that the drive returns some value to st_mode_sense
+ * incorrectly until the tape has actually passed by the head.
+ *
+ * The method is to set the drive to large fixed-block state (user-specified
+ * density and 1024-byte blocks), then read and rewind to get it to sense the
+ * tape. If that doesn't work, try 512-byte fixed blocks. If that doesn't
+ * work, as a last resort, try variable- length blocks. The result will be
+ * the ability to do an accurate st_mode_sense.
+ *
+ * We know we can do a rewind because we just did a load, which implies rewind.
+ * Rewind seems preferable to space backward if we have a virgin tape.
+ *
+ * The rest of the code for this quirk is in ILI processing and BLANK CHECK
+ * error processing, both part of st_interpret_sense.
+ */
+errval
+st_touch_tape(unit)
+ u_int32 unit;
+{
+ struct st_data *st = st_data[unit];
+ char *buf;
+ u_int32 readsiz;
+ errval errno;
- if (!silent && key > 0 && (key != 0x8 ||
- st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ)))
- {
- printf("st%d: %s", unit, error_mes[key - 1]);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- switch (key)
- {
- case 0x2: /* NOT READY */
- case 0x5: /* ILLEGAL REQUEST */
- case 0x6: /* UNIT ATTENTION */
- case 0x7: /* DATA PROTECT */
- break;
- case 0x8: /* BLANK CHECK */
- printf(", requested size: %d (decimal)",
- info);
- break;
- default:
- printf(", info = %d (decimal)", info);
- }
- }
- printf("\n");
- }
+ buf = malloc(1024, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return (ENOMEM);
- switch (key)
- {
- case 0x0: /* NO SENSE */
- case 0x1: /* RECOVERED ERROR */
- if(xs->resid == xs->datalen) xs->resid = 0;
- case 0xc: /* EQUAL */
- return(ESUCCESS);
- case 0x2: /* NOT READY */
- return(ENODEV);
- case 0x5: /* ILLEGAL REQUEST */
- return(EINVAL);
- case 0x6: /* UNIT ATTENTION */
- st->flags &= ~ST_PER_MEDIA;
- if (st->flags & ST_OPEN) /* TEMP!!!! */
- return(EIO);
- else
- return(ESUCCESS);
- case 0x7: /* DATA PROTECT */
- return(EACCES);
- case 0xd: /* VOLUME OVERFLOW */
- return(ENOSPC);
- case 0x8: /* BLANK CHECK */
- /***********************************************\
- * This quirk code helps the drive read the *
- * first tape block, regardless of format. That *
- * is required for these drives to return proper *
- * MODE SENSE information. *
- \***********************************************/
- if ((st->quirks & ST_Q_SNS_HLP) &&
- !(st->flags & ST_INFO_VALID))
- {
- st->blksiz -= 512;
- }
- else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ)))
- {
- st->flags |= ST_BLANK_READ;
- xs->resid = xs->datalen;
- return(ESUCCESS);
- }
+ if (errno = st_mode_sense(unit, 0)) {
+ goto bad;
+ }
+ st->blksiz = 1024;
+ do {
+ switch (st->blksiz) {
+ case 512:
+ case 1024:
+ readsiz = st->blksiz;
+ st->flags |= ST_FIXEDBLOCKS;
+ break;
default:
- return(EIO);
+ readsiz = 1;
+ st->flags &= ~ST_FIXEDBLOCKS;
+ } if (errno = st_mode_select(unit, 0)) {
+ goto bad;
}
- /***************************************************************\
- * If it's NOT code 70, just report it. *
- \***************************************************************/
- default:
- if (!silent)
- {
- printf("st%d: error code %d", unit,
- sense->error_code & SSD_ERRCODE);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" at block no. %d (decimal)",
- (sense->ext.unextended.blockhi << 16) +
- (sense->ext.unextended.blockmed << 8) +
- sense->ext.unextended.blocklow);
- }
- printf("\n");
+ st_read(unit, buf, readsiz, SCSI_SILENT);
+ if (errno = st_rewind(unit, FALSE, 0)) {
+bad: free(buf, M_TEMP);
+ return (errno);
}
- return(EIO);
- }
+ } while (readsiz != 1 && readsiz > st->blksiz);
+ free(buf, M_TEMP);
+ return 0;
}
diff --git a/sys/scsi/su.c b/sys/scsi/su.c
new file mode 100644
index 0000000..de4f017
--- /dev/null
+++ b/sys/scsi/su.c
@@ -0,0 +1,4 @@
+
+/* this will be a special user scsi device */
+/* not written yet */
+
diff --git a/sys/scsi/uk.c b/sys/scsi/uk.c
new file mode 100644
index 0000000..5c48d01
--- /dev/null
+++ b/sys/scsi/uk.c
@@ -0,0 +1,156 @@
+/*
+ * Dummy driver for a device we can't identify.
+ * by Julian Elischer (julian@tfs.com)
+ *
+ * $Id: uk.c,v 1.2 93/10/11 11:53:28 julian Exp Locker: julian $
+ */
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#define NUK 16
+
+/*
+ * This driver is so simple it uses all the default services
+ */
+struct scsi_device uk_switch =
+{
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "uk",
+ 0,
+ 0, 0
+};
+
+struct uk_data {
+ u_int32 flags;
+ struct scsi_link *sc_link; /* all the inter level info */
+} uk_data[NUK];
+
+#define UK_KNOWN 0x02
+
+static u_int32 next_uk_unit = 0;
+
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * a device suitable for this driver.
+ */
+errval
+ukattach(sc_link)
+ struct scsi_link *sc_link;
+{
+ u_int32 unit, i, stat;
+ unsigned char *tbl;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("ukattach: "));
+ /*
+ * Check we have the resources for another drive
+ */
+ unit = next_uk_unit++;
+ if (unit >= NUK) {
+ printf("Too many unknown devices..(%d > %d) reconfigure kernel\n",
+ (unit + 1), NUK);
+ return (0);
+ }
+ /*
+ * Store information needed to contact our base driver
+ */
+ uk_data[unit].sc_link = sc_link;
+ sc_link->device = &uk_switch;
+ sc_link->dev_unit = unit;
+
+ printf("uk%d: unknown device\n", unit);
+ uk_data[unit].flags = UK_KNOWN;
+
+ return;
+
+}
+
+/*
+ * open the device.
+ */
+errval
+ukopen(dev)
+{
+ errval errcode = 0;
+ u_int32 unit, mode;
+ struct scsi_link *sc_link;
+ unit = minor(dev);
+
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= NUK) {
+ printf("uk%d: uk %d > %d\n", unit, unit, NUK);
+ return ENXIO;
+ }
+
+ /*
+ * Make sure the device has been initialised
+ */
+ if((uk_data[unit].flags & UK_KNOWN) == 0) {
+ printf("uk%d: not set up\n", unit);
+ return ENXIO;
+ }
+
+ /*
+ * Only allow one at a time
+ */
+ sc_link = uk_data[unit].sc_link;
+ if (sc_link->flags & SDEV_OPEN) {
+ printf("uk%d: already open\n", unit);
+ return ENXIO;
+ }
+ sc_link->flags |= SDEV_OPEN;
+ SC_DEBUG(sc_link, SDEV_DB1, ("ukopen: dev=0x%x (unit %d (of %d))\n"
+ ,dev, unit, NUK));
+ /*
+ * Catch any unit attention errors.
+ */
+ return 0;
+}
+
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval
+ukclose(dev)
+{
+ unsigned char unit, mode;
+ struct scsi_link *sc_link;
+
+ sc_link = uk_data[unit].sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("Closing device"));
+ sc_link->flags &= ~SDEV_OPEN;
+ return (0);
+}
+
+/*
+ * Perform special action on behalf of the user
+ * Only does generic scsi ioctls.
+ */
+errval
+ukioctl(dev, cmd, arg, mode)
+ dev_t dev;
+ u_int32 cmd;
+ caddr_t arg;
+{
+ unsigned char unit;
+ struct scsi_link *sc_link;
+
+ /*
+ * Find the device that the user is talking about
+ */
+ unit = minor(dev);
+ sc_link = uk_data[unit].sc_link;
+ return(scsi_do_ioctl(sc_link,cmd,arg,mode));
+}
+
OpenPOWER on IntegriCloud