diff options
Diffstat (limited to 'sys/scsi')
-rw-r--r-- | sys/scsi/README | 189 | ||||
-rw-r--r-- | sys/scsi/cd.c | 2246 | ||||
-rw-r--r-- | sys/scsi/ch.c | 1204 | ||||
-rw-r--r-- | sys/scsi/scsi_all.h | 93 | ||||
-rw-r--r-- | sys/scsi/scsi_base.c | 852 | ||||
-rw-r--r-- | sys/scsi/scsi_cd.h | 10 | ||||
-rw-r--r-- | sys/scsi/scsi_changer.h | 9 | ||||
-rw-r--r-- | sys/scsi/scsi_debug.h | 53 | ||||
-rw-r--r-- | sys/scsi/scsi_disk.h | 11 | ||||
-rw-r--r-- | sys/scsi/scsi_ioctl.c | 329 | ||||
-rw-r--r-- | sys/scsi/scsi_tape.h | 12 | ||||
-rw-r--r-- | sys/scsi/scsiconf.c | 1110 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 259 | ||||
-rw-r--r-- | sys/scsi/sd.c | 2072 | ||||
-rw-r--r-- | sys/scsi/st.c | 3439 | ||||
-rw-r--r-- | sys/scsi/su.c | 4 | ||||
-rw-r--r-- | sys/scsi/uk.c | 156 |
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)); +} + |