.TITLE MKDRIVER - VAX/VMS SCSI Tape Class Driver .IDENT 'X-22' ; .LIST MEB ;**************************************************************************** ;* * ;* COPYRIGHT (c) 1978, 1980, 1982, 1984, 1986, 1988, 1991, 1992-1996 BY * ;* DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS. * ;* ALL RIGHTS RESERVED. * ;* * ;* THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED * ;* ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE * ;* INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER * ;* COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY * ;* OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY * ;* TRANSFERRED. * ;* * ;* THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE * ;* AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT * ;* CORPORATION. * ;* * ;* DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS * ;* SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. * ;* * ;* * ;**************************************************************************** ; ; ;+ ; ; FACILITY: ; ; VAX/VMS SCSI Tape Class Driver ; ; ABSTRACT: ; ; This module contains the class driver to control tape devices on ; a SCSI bus. ; ; ; AUTHOR: ; ; Jim Klumpp 13-Jan-1989 ; ; REVISION HISTORY: ; ; ?? Glenn Everhart ; Add "software front panel" latent density controls. ; If ucb$l_devdepnd3 is nonzero, use its value as a ; SCSI density. Otherwise normal. ; ; X-22 SCS Sue Sommer 2-Apr-1996 ; Modify SCSI_DEV_TYPES and the SCSI_DEVICE_TABLE to allow ; both sync mode and skpfile support to be table-controllable. ; ; X-21 GWW Grace Wang 29-Mar-1996 ; * Gryphon QAR 146: ; Fix cancel completion in IO_DIAGNOSE after current IRP ; has been returned with SS$_ABORT in MK_CANCEL earlier. ; This is a part of the solution which includes DKMK chan ; ; X-20 RCL Rick Lord 26-Mar-1996 ; Near the end of MK_KP_UNIT_INIT, just before the BSBW to ; SET_UNIT_ONLINE after 15$, invoke SPI$INITIAL_PROCESSING ; to run the common tolerant INQUIRY command routine. ; ; X-19 SCS Sue Sommer 20-Mar-1996 ; In IO_WRITEPBLK, modify the special path for 8MM devices. ; This path formerly used the same SCDRP for two consecutive ; write attempts; while it still does so now, it takes care ; to deallocate/reallocate the command buffer and unmap/remap ; the user buffer. This is necessary for smart adapters ; which assume a 1-1 correspondense between SCDRPs and requests. ; ; X-18 TGG0123 Tom Goodwin 15-Mar-1996 ; Add the TKZ60 to the list of skipfiles exclusions. ; ; X-17 SGS0088 Steve Skonetski 26-Feb-1996 ; Bump timeout values to 10 minutes. TLZ6L, 7L autoloaders ; timing out with 7 minute timeout values. ; ; X-16 MCY Mary Yuryan 28-Nov-1995 ; Add support for high SCSI ID's (wide devices). Change ; check in MK_KP_UNIT_INIT for valid SCSI ID's from 7 ; to 31. Clear calculation for higher LUN numbers. ; ; X-15 SCS Sue Sommer 4-Dec-1995 ; Re-instate skip-by-file, implementing fixes: ; - Return correct space count in IOSB. ; - Set EOF bit when appropriate. ; - Modify TRANS_SENSE_KEY to return ENDOFVOLUME properly. ; - Remove references to ucb$l_boff/bcnt. ; - Exempt TSZ05/7 from skipfile due to lack of BLANK CHECK. ; - Check the LOST bit in SPACE_FILEMARKS before exiting. ; - Rename skiprec_in_prog to skip_in_prog. ; - For skip count of 1 or 2, skip by record instead of by file; ; the overhead isn't worth it. ; - Rename for the sake of clarity: ; CHECK_READPOS_SUPPORT to CHECK_SKIPFILE_SUPPORT; ; UCB$V_READPOS_SUPPORTED to UCB$V_SKIPFILE_SUPPORTED; ; UCB$V_SKIPREC_INPROG to UCB$V_SKIP_INPROG. ; ; X-14 JCH710 John C. Hallyburton, Jr. 23-Oct-1995 ; STAR:: DOCD$:[EVMS.PROJECT_DOCUMENTS]FS-SCSI-NAMING.PS ; New Naming: Get controller letter from DDB$L_PORT_ID if ; DDB$V_PAC is set, indicating IOGEN copied the controller ; letter to DDB$L_PORT_ID before potentially folding the ; DDB$T_NAME controller letter to `A'. ; ; X-13 SCS Sue Sommer 29-Jun-1995 ; Modify MODE_SELECT so that the density field gets filled ; in for a TSZ07. ; ; X-12 RCL Rick Lord 10-May-95 ; Fold in the X-6U6 fix from Zeta: this fix adds bounds checking ; to MK_REG_DUMP just before label 35$, preventing the routine ; from overwriting the error log buffer entry it was handed and ; possibly corrupting the header of the error log buffer right ; after it. ; ; X-11 SCS Sue Sommer 19-Apr-1995 ; Turn off skipfile enhancement by unconditionally clearing ; the readpos_supported bit in ucb$l_mk_flags during unit init. ; This enhancement is deemed too risky for the current release ; and is planned for reinstatement in some future release ; after broader testing is completed. ; ; Modify the Mode Sense descriptors so that any Vendor Unique ; Required mode page values are now only Preferred. This is ; more compatible with the previous mode page handling and ; resolves unusual cases: eg. a Mode Select with vendor- ; unique values may return success but without actually ; setting the desired value, and that should count as success. ; ; Also create a new UCB field ucb$l_sav_send_status to save ; the return status from each SEND_COMMAND call. Restore ; that status in MODE_SENSE, since it was possibly overwritten ; by Do_Mode_Page, and the original SEND_COMMAND status must ; be returned by MODE_SENSE in order for all tapes to function ; properly (eg. SS$_MEDOFL was overwritten by SS$_NODATA, ; causing TURs not to be retried when they should have been). ; ; X-10 SCS Sue Sommer 11-Apr-1995 ; In the READ_POSITION routine, fix the sanity check regarding ; record position. Namely, for reverse skips, allow success ; whenever the new position is at beginning of tape. ; Previously, we checked that the new position was strictly ; less than old position, which did not account for BOT cases. ; ; X-9 MCY Mary Yuryan 27-Mar-1995 ; - Add the IF_TZK11 macro to retension the QIC media, the change ; was never ported from the VAX side. Add check in IO_RETENSION ; - Modify CHECK_READPOS_SUPPORT routine to check for TZK10 device ; type, - TZK10 does not support BT (block Type) bit of 0 - in ; the same routine, change the check from READPOS_IN_PROG bit, ; to READPOS_SUPPORTED bit - we were checking the wrong bit. ; ; X-8 JCH703 John C. Hallyburton, Jr. 13-Mar-1994 ; Add FAST_FDT offset to DDT for Fast-IO ; ; X-7 SCS Sue Sommer 14-Feb-1995 ; Declare various appropriate functions to be capable ; of supporting 64-bit addresses. ; ; X-6 SCS Sue Sommer 16-Nov-1994 ; Modify skipfile operation to use Space Filemarks instead ; of Skip Records wherever possible; major performance ; enhancement. Specific modifications: ; - Add READ_POSITION command to SCSI command table. ; - Add bits to ucb$l_mk_flags. ; - In PACKACK_SEQ, BSBW to a new routine CHECK_READPOS_SUPPORT. ; - In IO_SKIP_FILE, BSBW to a new routine SKIP_FILE. ; - In IO_SKIP_FILE, add new code to support SPACE FILEMARKS. ; - Exempt READ POSITION support checks from error logging ; in LOG_EXTND_SENSE. ; ; - Add keyword to SPI$CONNECT call for CLUE SCSI hooks. ; ; X-5 SCS Sue Sommer 11-Nov-1994 ; Correct delta time passed to exe$kp_tqe_wait. ; ; X-4 TEC Thomas E. Coughlan 7-OCT-1994 ; Back-out the change in X-15 that set the CLU bit. ; Tapes aren't supported on the shared bus in this ; version, so we can avoid the device naming disruption ; that is caused by setting this bit. ; ; X-3 JFD0660 James F. Dunham 28-SEP-1994 ; SCSI-2 Checkin ; ; ************* Change Edit History to Match CMS ******************** ; ; X-16 SCS Sue Sommer 7-Sep-1994 ; Change mode page descriptor for block descriptor to ; reflect only the density field, not the whole block ; descriptor. ; ; X-15 SCS Sue Sommer 6-Sep-1994 ; Modify SEND_COMMAND's Check Condition path to log ; errors even when the autosense data is invalid. ; Also set the CLU bit in DDTAB for SCSI clusters. ; ; X-14 SCS Sue Sommer 29-Aug-1994 ; In WRITEPBLK path, convert a leftover BSBW to CALL ; into SEND_COMMAND. ; ; X-13 SCS Sue Sommer 25-Aug-1994 ; Make the device specific parameter in the mode page ; header a Preferred rather than Required field to ; avoid a mode page verify error on the writelock bit. ; ; X-12 JFD0598 James F. Dunham 25-AUG-1994 ; Add $SCSIDEF (in more than just the comment field) ; ; X-11 SCS Sue Sommer 25-Aug-1994 ; Add $scsidef. ; ; X-10 SCS Sue Sommer 24-Aug-1994 ; Modify Check Condition path in SEND_COMMAND so that ; SCDRP$L_TRANS_CNT reflects the sense data length ; (not the the original command's trans_cnt) and ; the sense data can be correctly logged in errlog file. ; ; X-9 SCS Sue Sommer 22-Aug-1994 ; Add appropriate flags to mode descriptors for header fields, ; so they are treated as Required fields. ; ; X-8 SCS Sue Sommer 4-Aug-1994 ; Fix SCSI_DEV_TYPES macro so that DTYP offsets are correct. ; ; X-7 SCS Sue Sommer 27-JUL-1994 ; Add common mode sense and diagnose routines. ; Modify MODE_SENSE, MODE_SELECT, SETUP_COMPACTION. ; Add descriptors. ; Change SETUP_CMD, SEND_COMMAND, CLEANUP_CMD to call interfaces. ; Limit vendor-unique info to 8 bytes to fit in descriptor. ; Modify LOG_XTND_SENSE to not log ILLEGAL REQUEST errors. ; Move b_sense_key from UCB to SCDRP. ; ; X-6 SCS Sue Sommer 20-Jul-1994 ; Fix ucb$b_scsi_version to be fetched from proper INQUIRY field. ; ; X-5 SCS Sue Sommer 12-Jul-1994 ; Use scdrp$ps_kpb rather than unit_init_kpb to stall ; in exe$kp_tqe_wait in wait_unit_ready. ; ; X-4 SCS Sue Sommer 8-Jul-1994 ; Restore UCB address into R5 before calling KP_REQCOM in ; IO_DIAGNOSE. ; Fix bad time values for call to spi$tqe_wait. ; ; X-3 SCS Sue Sommer 6-Jul-1994 ; Remove references to ucb$l_scdrp_sav1 in request sense ; processing. ; ; X-32 SCS Sue Sommer 20-May-1994 ; Change SPI$xxx names for SCSI2. ; Replace SPI$TQE_WAIT with calls to exe$kp_tqe_wait. ; Modify SEND_COMMAND to handle Autosense. ; Modify SETUP_CMD, CLEANUP_CMD to allow previously allocated ; buffer. ; ; X-31 RAR028 Buzzy Ritter 20-Jan-1993 ; Add proper return values after forking in unit_init and ; ctrl_init. ; ; X-30 SGS0032 Steve Skonetski 25-oct-1993 ; Add callouts for new MME (Media Management Extenstion) ; facility. ; ; X-29 MCY Mary Yuryan 11-Oct-1993 ; In the SENSE_KEY_TABLE, change the error returned ; for BLANK CHECK from DRVERR to OPINCOMPL. This ; prevents a fatal drive error when performing ; multi-volume backups, on tapes that have not been ; initialized. ; ; X-28 LPL Lee Leahy 8-Oct-1993 ; ; ; X-27 RCL Rick Lord 1-Oct-1993 ; ; Add external symbol references to force failure to ; assembly phase rather than link. ; ; X-26 RCL Rick Lord ; ; Field name changes: ; ; SCDRP$V_S0BUF => SCDRP$V_FLAG_S0BUF ; SCDRP$M_S0BUF => SCDRP$M_FLAG_S0BUF ; SCDRP$V_BUFFER_MAPPED => SCDRP$V_FLAG_BUFFER_MAPPED ; SCDRP$M_BUFFER_MAPPED => SCDRP$M_FLAG_BUFFER_MAPPED ; SCDRP$V_DISK_SPUN_UP => SCDRP$V_FLAG_DISK_SPUN_UP ; SCDRP$M_DISK_SPUN_UP => SCDRP$M_FLAG_DISK_SPUN_UP ; ; X-25 WDA W.D. Arbo 20-Aug-1993 ; Change old step 2 macro names to new names. (E.g. ; $ABORTIO to CALL_ABORTIO). ; ; X-24 WDA W.D. Arbo 27-Jul-1993 ; More of X-23. ; ; X-23 WDA W.D. Arbo 29-Jun-1993 ; Tie up loose ends in step 2 conversion. ; ; X-22 NT014 Nora Tanner 11-May-1993 ; Filesystem structure promotions: WCB$W_NMAP has become a ; longword. ; ; X-21 RWC124 Richard W. Critz, Jr. 7-May-1993 ; I failed to notice that YELLOW found the wrong copy of this ; module when I checked in RWC122. As a result, the entry in the ; device table for the TZ85 is still commented out. Restore it ; to its rightful place. ; ; X-20 RWC122 Richard W. Critz, Jr. 23-Apr-1993 ; Integrate DDR support (in local routine GET_DEVICE_TYPE). ; ; X-19 WDA W.D.Arbo 18-Feb-1993 ; Convert driver to Step 2. ; ; Fix bug in LOG_ERROR. The IF_TZxx macros assume the UCB is in ; R3 but here it is in R5. This fix has been applied to the VAX ; side also. ; ; X-18 SCS Sue Sommer 24-Mar-1993 ; Add new devices to SCSI_DEV_TYPES table. ; ; X-17 SCS Sue Sommer 15-Mar-1993 ; In SETUP_COMPACTION, return an error whenever zero bytes ; of mode sense data are returned; prevents later crash ; when referencing SCDRP$L_SVA_USER. ; ; X-16 SCS Sue Sommer 15-Feb-1993 ; In the INIT_SCDRP routine, initialize SCDRP size and length ; fields to make crash dump analysis easier. ; ; X-15 SCS Sue Sommer 13-Nov-1992 ; Rename ALLOC_POOL to MK_ALLOC_POOL and insure that all calls ; to it have KPB address in R5. ; ; Modify DO_8MM_COPY_CHK to unmap and then re-map the data ; buffer after a READ_8MM command. This accommodates those ; platforms which always unmap a buffer when the command ; buffer is deallocated. ; ; Merge in Blade changes to the level of X-25: (Exclude C2 ; changes, DDR support, allocation of SCDRP for REQUEST_SENSE; ; also, 8MM changes had already been merged earlier.) ; ; MCY Mary Yuryan / Rick Lord 17-Sep-1992 ; - Enhance loader support, delete old CHECK_FOR_LOADER macro, ; Add loader byte to SCSI_DEV_TYPES1, check for loader in ; GET_DEVICE_TYPE, add loader byte to device string in ; SCSI_DEV_TYPES. RCL ; - In LOG_EXTND_SENSE, add check for BOT and BLANK CHECK error ; & supress logging the error - for new tapes. MCY ; - Add check for cancelled IO in IO_SENSECHAR: to avoid reading ; cancelled IO/deallocated IRP. RCL ; (SENSECHAR not cancellable in Alpha /SCS 13-Nov-1992) ; - Complete TKZ09 support - add check for TKZ09 after check for ; 8mm tape in GET_DEVICE_TYPE. ; - Merge in John Meneghini's fixes below. MCY ; ; JAM0008 John Meneghini 23-JUL-1992 ; Lengthen Disconnect & DMA/Phase change timeouts with ; ERASE, SPACE and RECIEVE DIAGNOSTICS commands. ; - Increased DISCONNECT timeouts to 5 hours w/ SPACE & ERASE ; - Increased DMA timeouts to 1 min. w/ RECIEVE_DIAGNOSTICS ; ; JSSBLADE John S. Simakauskas 24-June-1992 ; Add TKZ09 - 5GB, 8mm, SCSI Tape (TKZ08 Follow-on) ; ; JAM001 John Meneghini 06-MAY-1992 ; Branch around INSV instruction in GET_DEVICE_TYPE routine ; setting MT$S_DENSITY field in UCB$_DEVDEPEND. Was ; improperly resetting Compaction (to zero) w/TLZ06. ; ; MCY Mary Yuryan 25-Feb-1992 ; Merge loader support from Amber. Create the CHECK_FOR_LOADER ; macro which will set the loader bit if TZ857 or TLZ6 is ; present, called from the INQUIRY routine. ; Sync the VSC idents... ; ; MCY Mary Yuryan 20-Dec-1991 ; Add latent support for SCSI loaders - TKZ60, TZ857, ; TZ867,TZ877, and TLZ6 (TLZ06 loader.) ; ; FAK002 Forrest A. Kenney 26-Nov-1991 ; Merge in latest Blade changes. ; ; WJG0049 W. John Guineau 15-Nov-1991 ; Add DDR support. (Comment for Alpha /SCS 13-Nov-1992) ; ; DWF0022 David W. Freund 12-Nov-1991 ; Fold in X-16A1 by W. John Guineau: ; - Fix bug introduced in X-16 for rewind timout check ; WAIT_UNIT_READY - add a BRB around UNLOAD timeout ; code path. ; ; WJG W. John Guineau 8-Oct-1991 ; - Fix EXABYTE (8MM) DCL COPY command problems. ; - Fix resource contention problems due to dma buffer ; deadlock conditions when a SCSI error occurs and all ; buffer space is allocated. Now we allocate enough ; mapping resources at UNIT_INIT in ALLOC_REQSNS_RESOURCE ; for the REQUEST SENSE to get through (which was prevoiusly ; hanging waiting for resources which were locked until the ; REQUEST SENSE completed, which coudn't because it couldn't ; get resources to execute!) ; (Note: Irrelevant for Alpha, not merged due to lack ; of DMA buffer contention /SCS 13-Nov-1992) ; ; Forrest A. Kenney 07-Nov-1991 ; Merge in MAGIC and BLADE changes since T2 snapshot. ; ; WJG W. John Guineau 7-Oct-1991 ; - Change unload timeout logic from X-15 to use separate ; bit (UCB$M_UNLOAD_INPROG not UCB$M_REWIND_INPROG) ; and time field (UCB$L_UNLOAD_TIME) so we don't hang on ; IO$_AVAILABLE after a DISMOUNT. This is necessary ; since we must not timeout after an UNLOAD with media ; stackers for at least 3 minutes to give the stacker ; time to get the next tape loaded. ; ; WJG W. John Guineau 1-Oct-1991 ; - Add REWIND timeout logic to IO_UNLOAD code path to ; prevent loaders from timwing out while traversing a ; media stack. ; - Make ident match VSC ident ; ; FAK001 Forrest A. Kenne 23-Sep-1991 ; Merge C2 changes into Blade. Make module ident and revision ; history agree with CMS after the master pack cleanup. ; (C2 changes not merged for Alpha /SCS 13-Nov-1992) ; ; WJG W. John Guineau 14-Aug-1991 ; Return the compaction "density" values in the sense mode ; data packet for BACKUP. ; ; WJG W. John Guineau 22-May-1991 ; Add UCB$V_COMPCHK_IN_PROG bit to flag when compaction ; check is in progress to prevent bad scsi status on ; devices which don't support compaction from setting tape ; lost ; ; WJG W. John Guineau 15-May-1991 ; Fix DMA Length field in MODE_SENSE_COMP SCSI_CMD ; descriptor to be the exact value of data in expected ; to work around a data pointer manipulation bug in ; PKIDRIVER ; ; X-14 SCS Sue Sommer 27-Oct-1992 ; Modify LOG_ERROR routine to write EMB$L_DV_STS, EMB$L_DV_ERTCNT ; and EMB$L_DV_ERTMAX in error buffer, since otherwise they ; contain uninitialized data; also zero EMB$Q_DV_IOSB, since ; the IOSB is not yet known at this point. ; ; X-13 SCS Sue Sommer 1-Oct-1992 ; In LOG_ERROR macro and LOG_ERROR and REGDUMP routines, replace ; use of R7 and R8 with UCB fields. This accommodates ERL$DEVxxx ; convention, which does not declare R7 and R8 as inputs. ; ; X-12 SCS Sue Sommer 9-Sep-1992 ; Increase ERASE timeout value to 5 hours to accommodate ; 90m TLZ06 tape. ; Disallow cancel operations for SENSEMODE/SENSECHAR/SETMODE; ; otherwise the canceled IRP will sometimes be given to ; another device before the canceled I/O completes, resulting ; in simultaneous use of that IRP by two devices. (Only these ; 3 functions reference the IRP after the cancel occurs.) ; ; X-11 SCS Sue Sommer 20-Jul-1992 ; Merge in John Guineau's VAX bug fix for the EXABYTE (8MM ; TKZ09) DCL COPY problems. ; ; X-10 SFS0563 Stephen F. Shirron 06-Jul-1992 ; Add new SCSI devices. ; ; X-9 SCS Sue Sommer 27-May-1992 ; Add new devices to SCSI device table. ; ; X-8 SCS Sue Sommer 8-Apr-1992 ; Include symbol alignment for UCB extensions. ; Merge in VAX/VMS V5.4-3 changes by John Guineau, Mary ; Yuryan, Howard Palmer as follows: ; ; Add UCB$V_COMPCHK_IN_PROG bit to flag when compaction ; check is in progress to prevent bad scsi status on ; devices which don't support compaction from setting tape ; lost ; ; Fix DMA Length field in MODE_SENSE_COMP SCSI_CMD ; descriptor to be the exact value of data in expected ; to work around a data pointer manipulation bug in ; PKIDRIVER ; ; More compaction fixes - this time with real hardware to test ; on! Moved check for compaction support into separate ; routine CHECK_COMPACTION_SUPPORT, utilized MT2$V_COMP_ENA ; bit in DEVDEPND2 instead of density field. Also, now ; returns SS$_NORMAL if you set a density a device doesn't ; support (previous behaviour) - CHECK_COMPACTION_SUPPORT is ; called from UNIT_INIT (via SET_UNIT_ONLINE) and from PACKACK. ; ; Allow SCSI-1 compliant devices to be used. The check added ; in X-18U3 only allowed SCSI-2 via UCB$B_SCSI_VERSION ; ; Merge Magic and Sigma code streams ; ; Remove default mode_select parameters from the SCSI_DEV_ ; TABLES for the TSZ05,(TZX0) & TSZ07. The RDEW bit caused ; mutiple volume backup problems when set, causing the backup ; operation to fail. ; ; Make data compaction support more generic for SCSI ; in VMS. Enable automatic recognition of devices which ; support compaction. Add DISABLE/REENABLE_ERRLOG macros ; from DKDRIVER. Add UCB$B_SCSI_VERSION field in UCB for ; recognition of SCSI2 compliant devices. ; ; Add TZK11 and TLZ06 data compaction support. ; ; Change default mode_select paramters for the TSZ05, ; TSZ07 to fix the multi-volume backup failures with ; the RDEW bit set. ; ; ------------ Ident change due to master pack cleanup ----------- ; ; X-19 SCS Sue Sommer 8-Mar-1992 ; Remove the TRACE_TABLE since the cross-PSECT offsets it contains ; prevent the "sliced" loading of this driver. Moreover, this ; table is unused in this version of this driver. Finally, in ; macro MK_ALLOC_SCDRP, assure that the SCDRP allocated on the ; stack is quadword aligned for performance reasons. ; ; X-18 SCS Sue Sommer 23-Feb-1992 ; Remove END keyword in DPT so driver may be sliced. ; Remove unreachable code in MK_SENSEMODE. ; ; X-17 ROW0802 Ralph O. Weber 28-JAN-1992 16:20 ; Fix the unit routine to start the KP stack usage with a ; KP register save mask that is suitable for HLL port drivers. ; The Cobra port driver is HLL and needs this fix. ; ; X-16 SCS Sue Sommer 17-Jan-1992 ; Edit IF*_* macros to allow a UCB macro argument. In ; FILTER_ERROR, call IFNOT_TK with UCB=R5. ; ; X-15 BJT291 Benjamin J. Thomas III 9-Jan-1992 ; Promote UCB ERRCNT, ERTCNT and ERTMAX fields to longwords ; ; X-14 BJT286 Benjamin J. Thomas III 5-Dec-1991 ; Use HLL KPB register mask rather than hand built one ; ; X-13 BJT277 Benjamin J. Thomas III 21-Nov-1991 ; Use IRP for passing of QIO arguments P1 - P6 ; ; X-12 BJT271 Benjamin J. Thomas III 15-Nov-1991 ; Promote FUNC fields ; ; X-11 BJT265 Benjamin J. Thomas III 11-Nov-1991 ; More UCB, IRP promotions to longword. ; ; X-10 SCS Sue Sommer 6-Nov-1991 ; In IO_SKIP_RECORD and IO_SKIP_FILE, copy SCDRP$L_MEDIA ; correctly. In FILTER_ERROR, fill error array correctly. ; ; X-9 BJT260 Benjamin J. Thomas III 31-Oct-1991 ; More promotions to longword. UCB BOFF, IRP BOFF and BCNT ; ; X-8 SCS Sue Sommer 7-Oct-1991 ; Promote SCDRP$W_STS to SCDRP$IS_STS and convert remaining ; occurrences of IRP$W_STS to IRP$L_STS. ; Also replace the double fork in unit init with a fork-and-wait ; mechanism. ; ; Merge in changes by Mary Yuryan, Barbara Leahy, Jim Klumpp, ; and Howard Palmer from VAX/VMS V5.4-2 as follows: ; In RETENSION support, change status of drive to be ; "valid" and "online" after the RETENSION operation. ; Move the TZK10 RETENSION function from SKIPFILES to ; the UNLOAD and REWIND functions. Add TLZ06 tape symbol, ; next generation RDAT. ; Change the algorithm for determining whether a device ; is not ready due to a previous rewind/immediate command. ; Before, the driver would always assume a rewind was in ; progress and wait at least the maximum rewind time before ; timing out a wait unit ready polling loop. Now, whenever ; a rewind/immediate is sent to the drive, the time by which ; this command should complete is recorded in the UCB. This ; information can then be used to time out wait unit ready ; polling activity. ; Add a workaround for the TZK50 phase error bug. Delay for ; one second after sending a SCSI unload command to the TZK50 ; to prevent subsequent test unit ready commands from being ; told the device is ready, when in fact it's really in the ; process of being rewound and unloaded. ; Add the RETENSION command for the TZK10 tape drive. ; Create new SCSI command packet for "RETENSION" using ; the SCSI "LOAD" command. Created modifier IO$M_RETENSION ; IODEF for IO$_SKIPFILE function code. Created IFNOT_TZK10 ; macro to check for proper device type. ; Remove the very short timeout period for the TSZ07 ; in the WAIT_UNIT_READY: routine. The current timeout ; caused DCL commands such as mount/init to timeout while ; waiting for the tape to rewind. ; Add support for 9-track, dual density TSZ07 device. ; IO_SETMODE, IO_SENSEMODE routines modified to provide ; setting/reporting of TSZ07 density. Return SS$_DATAOVERUN ; status if a read fails with ILI status and the user ; requested less data than was in the actual record. ; ; X-7 BJT247 Benjamin J. Thomas III 27-Sep-1991 ; Promote IRP$W_STS to IRP$L_STS ; ; X-6 SCS Sue Sommer 4-Sep-1991 ; Modify unit routine to save the UCB address in the KPB before ; calling KP_SWITCH_TO_KP_STACK, and to restore it afterwards. ; ; X-5 SCS Sue Sommer 12-Jul-1991 ; Fix argument in call to KP_ALLOCATE_KPB. ; ; X-4 SCS Sue Sommer 2-Jul-1991 ; Modify unit initialization routine to deallocate KPB ; after unit init completes. ; ; X-3 SCS Sue Sommer 22-Mar-1991 ; Miscellaneous cleanup for alignment. Sanity check minimum ; rev level argument for its proper length in SCSI_DEV_TYPES. ; ; ----------Version number change due to reorg of master pack ----------- ; ; X-1K2 SCS Sue Sommer 21-Feb-1991 ; Initial Alpha changes. ; ; X-14K2 LSS0168 Leonard S. Szubowicz 14-Sep-1990 ; Fork block FR3 and FR4 have each been expanded to a quadword ; to allow the preservation of their full 64-bit values on EVAX. ; Use MOVX macro to copy these quantities in an architecture ; independent fashion. ; ; X-15 JTK Jim Klumpp 06-Jun-1990 ; In SETUP_CMD, map the buffer with high priority to avoid ; deadlock. The map buffers elsewhere can remain at low ; priority, as there's no danger of deadlock on the first ; call to map buffer per QIO function. ; ; X-14 MCY Mary Yuryan 06-Mar-1990 ; Increase SCSI command timeout values to match those ; of the RDAT tape drive. Increase the default timeout ; from 4 seconds to 30 seconds. Add new inquiry entry ; for ucode change made to fix PVAX console output. ; Add device name for QIC tape - TZK10. ; ; X-13 JTK Jim Klumpp 23-Jan-1990 ; Fix rewind/immediate. The command following a ; rewind/immediate can fail if the rewind is still in ; progress. Call the wait unit ready routine in this ; situation to prevent the new command from failing. ; ; X-12 MCY Mary Yuryan 18-Jan-1990 ; Fix device identification field returned by the ; inquiry command that changed with new micro-code. ; ; X-11 JTK Jim Klumpp 5-Jan-1990 ; Fix revision checking. Bring a drive online whether it's ; out of rev or not (to prevent problems during installation). ; ; X-10 MCY Mary Yuryan 28-Dec-1989 ; Add TLZ04 (RDAT) tape support. ; ; X-9 JTK Jim Klumpp 28-Sep-1989 ; Merge changes from 5.3 stream including: ; ; X-7U2 JTK Jim Klumpp 25-Sep-1989 ; Fix read/reverse bug. Remove revision checking of ; third party drives. Decrease mount timeout time. ; ; X-7U1 DGB0318 Donald G. Blair 05-Aug-1989 ; Add DPT$V_NO_IDB_DISPATCH bit to the driver prologue table. ; ; X-8 JTK Jim Klumpp 4-Aug-1989 ; Change logical end of volume handling to ignore the ; mount status. Fix ident to match master pack. ; ; X-6 JTK Jim Klumpp 22-Jun-1989 ; Add callback support and data structure version ; checking for SPI$CONNECT. Remove TZ30-specific timeout ; support. Add fastboot support. Fix bug in IO_SKIP_RECORD_REV. ; Add IO_WRITEMARK routine which is equivalent to IO_WRITEOF. ; Translate all media errors to SS$_PARITY. Add density field ; to device type table. Fix multi volume test code. Add ; workaround for tapemark handling synchronization bug. ; Remove $SCDTDEF macro. Change number of arguments passed ; to SET_CONN_CHAR. Change priv needed for IO_DIAGNOSE function. ; ; X-5 JTK Jim Klumpp 16-Jun-1989 ; Add TZ30-specific timeout values, retry in SEND_COMMAND ; if drive returns BUSY status, several minor bugfixes. ; ; X-4 JTK Jim Klumpp 1-Jun-1989 ; Add more robust checking of the additional field in ; extended sense data. ; ; X-3 JTK Jim Klumpp 12-May-1989 ; SCSI tape class driver: complete replacement of ; PVAX monolithic tape driver. ;- .PAGE .SBTTL + .SBTTL + SYMBOL DEFINITIONS .SBTTL + .SBTTL External symbol definitions ; ; External symbols ; $CANDEF ; Cancel reason codes $CRBDEF ; Channel request block $DCDEF ; Device classes and types $DDBDEF ; Device data block $DEVDEF ; Device characteristics ;;; $DTNDEF ; DDR DTN offsets ;;; $DTUDEF ; DDR DTU offsets $DYNDEF ; Data strucure types $EMBDEF ; Errorlog message buffer $FDTARGDEF ; Define FDT routine input arg offsets $FDT_CONTEXTDEF ; Define FDT context structure $FKBDEF ; Define fork block symbols $IDBDEF ; Interrupt data block $IODEF ; I/O function codes $IPLDEF ; Hardware IPL definitions $IRPDEF ; I/O request packet $KPBDEF ; Kernel process block symbols $MMEDEF ; Media Management defs $MODEDEF ; Mode page handling defs $MTDEF ; Magtape status codes $MT2DEF ; Extended Magtape status codes $NSADEF ; Security symbols $ORBDEF ; Object rights $PCBDEF ; Process control block $PRVDEF ; Privilege mask $PTEDEF ; Page table entry symbols $SCDRPDEF ; SCSI SCDRP symbols $SCSIDEF ; SCSI Definitions $SPDTDEF ; SCSI PDT symbols $SPIDEF ; SCSI port interface $SSDEF ; System status codes $UCBDEF ; Unit control block $VADEF ; Virtual address symbols $VECDEF ; Interrupt vector block $WCBDEF ; Window control block .DISABLE GLOBAL ; ; Define external references to force failure to assembly phase rather ; than being deferred until linking. ; .EXTERNAL ACP_STD$ACCESS .EXTERNAL ACP_STD$DEACCESS .EXTERNAL ACP_STD$FASTIO_BLOCK .EXTERNAL ACP_STD$MODIFY .EXTERNAL ACP_STD$MOUNT .EXTERNAL ACP_STD$READBLK .EXTERNAL ACP_STD$WRITEBLK .EXTERNAL BUG$_INCONSTATE .EXTERNAL CLU$GL_ALLOCLS .EXTERNAL COM$DRVDEALMEM .EXTERNAL DO_MODE_PAGE .EXTERNAL EXE$ALONONPAGED .EXTERNAL EXE$ALONONPAGED_ALN .EXTERNAL EXE$ALOPHYCNTG .EXTERNAL EXE$DEANONPAGED .EXTERNAL EXE$DEANONPGDSIZ .EXTERNAL EXE$DEBIT_BYTCNT_ALO .EXTERNAL EXE$GL_ABSTIM .EXTERNAL EXE$GL_HBS_PTR .EXTERNAL EXE$GL_SHADOW_SYS_DISK .EXTERNAL EXE$GL_SYSUCB .EXTERNAL EXE$GQ_SYSTYPE .EXTERNAL EXE$INSTIMQ .EXTERNAL EXE$KP_ALLOCATE_KPB .EXTERNAL EXE$KP_FORK_WAIT .EXTERNAL EXE$KP_RESTART .EXTERNAL EXE$KP_STALL_GENERAL .EXTERNAL EXE$KP_START .EXTERNAL EXE$KP_TQE_WAIT .EXTERNAL EXE$OUTZSTRING .EXTERNAL EXE_STD$ABORTIO .EXTERNAL EXE_STD$INSIOQ .EXTERNAL EXE_STD$READLOCK .EXTERNAL EXE_STD$FINISHIO .EXTERNAL EXE_STD$ALLOCIRP .EXTERNAL CTL$GL_PCB .EXTERNAL DKMK$DIAGNOSE_INIT .EXTERNAL DKMK$DIAGNOSE_FDT .EXTERNAL DKMK$DIAGNOSE_SIO .EXTERNAL EXE_STD$MODIFYLOCK .EXTERNAL EXE_STD$KP_STARTIO .EXTERNAL EXE_STD$LCLDSKVALID .EXTERNAL EXE_STD$ONEPARM .EXTERNAL EXE_STD$SENSEMODE .EXTERNAL EXE_STD$SETMODE .EXTERNAL EXE_STD$READCHK .EXTERNAL EXE_STD$WRITECHK .EXTERNAL EXE_STD$WRITELOCK .EXTERNAL EXE_STD$ZEROPARM .EXTERNAL IOC$ADD_DEVICE_TYPE .EXTERNAL IOC$GL_SPDT_LIST .EXTERNAL IOC$GL_SPI_CONNECT .EXTERNAL IOC$PTETOPFN .EXTERNAL IOC$REMOVE_DEVICE_TYPE .EXTERNAL IOC$REQCOM .EXTERNAL IOC$RETURN .EXTERNAL IOC$RETURN_UNSUPPORTED .EXTERNAL LDR$ALLOC_PT .EXTERNAL LDR$DEALLOC_PT .EXTERNAL MME$$DEV_EVENT .EXTERNAL MMG$GL_BWP_MASK .EXTERNAL MMG$GL_BWP_MASK .EXTERNAL MMG$GL_PAGE_SIZE .EXTERNAL MMG$GL_PTE_OFFSET_TO_VA .EXTERNAL MMG$GL_SPTBASE .EXTERNAL MMG$GL_VA_TO_VPN .EXTERNAL MMG$GL_VPN_TO_VA .EXTERNAL MMG$SVAPTECHK .EXTERNAL MMG$TBI_SINGLE .EXTERNAL MT_STD$CHECK_ACCESS .EXTERNAL SCS$GL_MSCP_NEWDEV .EXTERNAL SMP$AL_IPLVEC .EXTERNAL SMP$GL_FLAGS .EXTERNAL SYS$AR_BOOTUCB .EXTERNAL IOC$CRAM_IO .EXTERNAL IOC$CRAM_CMD .EXTERNAL IOC$NODE_FUNCTION .EXTERNAL EXE$GL_CPUNODSP .EXTERNAL IOC$ALLOC_CRAB .EXTERNAL IOC$KP_WFIKPCH .EXTERNAL EXE$KP_FORK .EXTERNAL ERL_STD$DEVICEATTN .EXTERNAL EXE$TIMEDWAIT_SETUP .EXTERNAL EXE$TIMEDWAIT_COMPLETE .EXTERNAL IOC$LOAD_MAP .SBTTL Misc local symbols ; ; Local symbols ; LOADER = 1 ; Specify that a device is a loader - ; mcy / rcl - 9/18/92 ; DEBUG = 1 ; Flag to enable various tracing and ; debug features. .IF DEFINED DEBUG .PRINT ; - DEBUG flag is enabled .ENDC ; MULTI_VOLUME_TEST = 1 ; Flag to enable multi-volume tape ; testing by causing ENDOFTAPE status ; to be returned on any writes after ; record 100 (hex). .IF DEFINED MULTI_VOLUME_TEST .PRINT ; - Remove code to test multi-volume tapes .ENDC SCDRPS_PER_UNIT = <3+1> ; Number of SCRPs to allocate per unit READY_POLL_INTERVAL = 1 ; Interval for test unit ready polling BUSY_RETRY_CNT = 10 ; Number of times to retry sending ; command if device is busy MAX_BCNT = 65535 ; Maximum byte count per transfer DEFAULT_DISCONNECT_TIMEOUT = 30 ; Default values in seconds for disconnect DEFAULT_PHASE_CHANGE_TIMEOUT = 30 ; and phase change timeouts MK_ERROR_REVISION = 2 ; Errorlogging revision supported by ; this driver. This should be incremented ; each time an incompatible change is ; made to the errorlog packet format. MAX_REWIND_TIME = 3*60 ; Maximum time a rewind command should ; take MAX_UNLOAD_TIME = 3*60 ; Maximum time an unload command should ; take DEF_TAPE_PARAMS = - ; Default tape parameters: !- ; default density ; BLK_833 format BPU_BIT = 2 ; Block position unknown in READ POS data .SBTTL SCSI status codes ; Define SCSI status codes SCSI$M_STAT_MASK = ^XE1 ; SCSI status byte mask SCSI$C_GOOD_STATUS = 0 ; Good (normal) status SCSI$C_CHK_CONDITION = 2 ; Check condition (send a request sense) SCSI$C_BUSY = 8 ; Device is busy .SBTTL Peripheral devices types ; Peripheral device type returned by the INQUIRY command SCSI$C_TAPE = 1 ; Tape device .SBTTL Sense key codes ; Define SCSI sense key codes. SCSI$C_NO_SENSE = 0 ; No sense data SCSI$C_RECOVERED_ERROR = 1 ; Recovered error (treated as success) SCSI$C_NOT_READY = 2 ; Device not ready SCSI$C_MEDIUM_ERROR = 3 ; Medium (parity) error SCSI$C_HARDWARE_ERROR = 4 ; Hardware error SCSI$C_ILLEGAL_REQUEST = 5 ; Illegal request SCSI$C_UNIT_ATTENTION = 6 ; Unit attention (media change, reset) SCSI$C_DATA_PROTECT = 7 ; Data protection (writelock error) SCSI$C_BLANK_CHECK = 8 ; Blank check (advance past end of data) SCSI$C_VENDOR_UNIQUE = 9 ; Vendor unique key SCSI$C_COPY_ABORTED = 10 ; Copy operation aborted SCSI$C_ABORTED_COMMAND = 11 ; Command aborted SCSI$C_EQUAL = 12 ; Compare operation, data match SCSI$C_VOLUME_OVERFLOW = 13 ; Write beyond physical end of tape SCSI$C_MISCOMPARE = 14 ; Compare operation, data mismatch SCSI$C_RESERVED = 15 ; Reserved ; Define one additional sense code. This particular one is used to distinguish ; between fatal and non-fatal medium errors. In a medium error sense key is ; returned and the additional sense code is uncorrectable ECC error, then return ; SS$_PARITY status but continue to process commands for this device. Otherwise, ; set position list as the media error may have caused the tape to loose its ; position. SCSI$C_UNCORECT_ECC = ^X11 ; Uncorrectable ECC error ; Define offsets in various SCSI command packets. SCSI_XS$B_ERR_CODE = 0 ; Extended sense error code SCSI_XS$B_KEY = 2 ; Extended sense KEY field SCSI_XS$V_KEY = 0 ; Extended sense KEY bit number SCSI_XS$S_KEY = 4 ; Extended sense KEY length SCSI_XS$B_ADDNL_INFO = 3 ; Extended sense additional code SCSI_XS$B_ADDNL_CODE = 12 ; Extended sense additional code SCSI_XS$B_ADDNL_CODE30 = 8 ; " " (TZ30) SCSI_XS$B_ADDNL_CODE50 = 8 ; " " (TZK50) SCSI_XS$M_EOF = ^X80 ; Extended sense end of file SCSI_XS$M_EOM = ^X40 ; Extended sense end of medium SCSI_XS$M_ILI = ^X20 ; Extended sense illegal length indicator SCSI_XS$V_ADDNL_VALID = 7 ; Extended sense additional data valid SCSI_WFM$B_CNT = 2 ; Write filemarks count SCSI_RD$B_LEN = 2 ; Read transfer length SCSI_WRT$B_LEN = 2 ; Write transfer length SCSI_RWND$B_IMMED = 1 ; Rewind immediate flag SCSI_INQ$B_DEVTYPE = 0 ; Inquiry device type SCSI_INQ$B_DEVQUAL = 1 ; Inquiry device qualifier field SCSI_INQ$V_DEVQUAL = 0 ; Inquiry device qualifier starting bit SCSI_INQ$S_DEVQUAL = 7 ; Inquiry device qualifier length SCSI_INQ$V_REMOVABLE = 7 ; Inquiry removable bit SCSI_SKIP$B_CNT = 2 ; Skip record count SCSI_RCVD$B_HW_REV = 0 ; Receive diagnostic HW revision field SCSI_RCVD$B_SW_REV = 1 ; Receive diagnostic SW revision field SCSI_MSNS$B_WP = 2 ; Mode sense write protect field SCSI_MSNS$V_WP = 7 ; Mode sense write protect bit SCSI_MSNS$B_BLOCK = 3 ; Mode sense block descriptor length SCSI_MSNS$V_BLOCK = 3 ; Mode sense block descriptor bit SCSI_MSNS$B_DENSITY = 4 ; Mode sense density code SCSI_MSEL$W_RSVD0 = 0 ; Mode select reserved SCSI_MSEL$B_SPEED = 2 ; Mode select speed field SCSI_MSEL$B_MODE = 2 ; Mode select buffered mode SCSI_MSEL$B_DSCLEN = 3 ; Mode select record descriptor length SCSI_MSEL$C_DSCLEN = 8 ; Mode select record descriptor length SCSI_MSEL$B_DENS = 4 ; Mode select density SCSI_MSEL$B_BLOCKS = 5 ; Mode select number of blocks SCSI_MSEL$B_RSVD1 = 8 ; Mode select reserved SCSI_MSEL$B_BLKLEN = 9 ; Mode select block length SCSI_MSEL$B_VULEN = 12 ; Mode select vendor unique length SCSI_MSEL$B_VU = 13 ; Mode select vendor unique field SCSI_MSEL$M_BUF = ^X10 ; Mode select buffered mode SCSI_MSEL$B_COMP = 14 ; Mode select data compression algorithm SCSI_MSEL$M_NOF = 7 ; Number of fillers for generic device SCSI_MSEL$M_NOF50 = 7 ; Number of fillers for TZK50 SCSI_MSEL$M_NOF30 = ^X0F ; Number of fillers for TZ30 SCSI_MSEL$M_RESEL = ^X40 ; Reselection timeout flag ; Get/set connect characteristics symbols. SET_CON$L_LEN = 0 ; Length field SET_CON$L_CON_FLAGS = 4 ; Flags field SET_CON$M_DISC = 1 ; Enable disconnect flag SET_CON$M_NORETRY = 2 ; Disable command retry flag SET_CON$L_SYN_FLAG = 8 ; Synchronous flag field SET_CON$M_SYN = 1 ; Synchronous flag ; Request Sense resource REQSNS_SIZE = 19 ; 19 bytes for request sense data .PAGE .SBTTL Tape class driver extensions to the UCB ; ; Tape class driver extensions to the UCB. ; .SYMBOL_ALIGNMENT QUAD $DEFINI UCB ; Start of UCB definitions . = UCB$K_LCL_TAPE_LENGTH $DEF UCB$L_HW_REV .BLKL 1 ; Hardware revision field $DEF UCB$PS_UNITINIT_KPB .BLKL 1 ; Pointer to KPB allocated in unit init $DEF UCB$L_SCDRP .BLKL 1 ; Address of active SCDRP $DEF UCB$L_SCDRP_SAV1 .BLKL 1 ; Address of saved SCDRP $DEF UCB$L_KPB_SAV1 .BLKL 1 ; Address of saved KPB $DEF UCB$L_FLUSH_IOQFL .BLKL 1 ; I/O flush queue forward link $DEF UCB$L_FLUSH_IOQBL .BLKL 1 ; I/O flush queue backward link $DEF UCB$L_ERR_MASK .BLKL 1 ; Mask of error types logged so far $DEF UCB$B_ERR_ARRAY .BLKB 16 ; Saved error array used to filter errors $DEF UCB$L_SCDT .BLKL 1 ; SCDT address $DEF UCB$L_MK_FLAGS .BLKL 1 ; Class driver flags $VIELD UCB,0,<- ; ,- ; Removable media ,- ; Wait for unit ready in progress ,- ; Device supports disconnect ,- ; Device supports synchronous operation ,- ; Disable errorlogging ,- ; Reverse motion in progress ,- ; Additional data is valid ,- ; Skip file/record operation in progress ,- ; Rewind operation may still be active ,- ; Unload operation may still be active ,- ; Compaction support check in progress ,- ; Device is an 8MM device ,-; Device supports READ POSITION cmd ,- ; Space filemarks operation in progress ,-; READ POSITION support check in progress ,-; Position should not be updated >; Set until first READ POSITION completes $DEF UCB$L_ADDNL_INFO .BLKL 1 ; Additional extended sense info $DEF UCB$L_PREV_TM .BLKL 1 ; Position on tape of last filemark $DEF UCB$L_MIN_REV .BLKL 1 ; Minimum revision level $DEF UCB$L_MSEL_INFO .BLKL 1 ; Pointer to vendor-unique mode select info $DEF UCB$L_COMP_PAGE .BLKL 1 ; Pointer to mode select page 10 (compaction) $DEF UCB$L_TR_QIO_STS .BLKL 1 ; Address in trace buf to put QIO status $DEF UCB$L_REWIND_TIME .BLKL 1 ; Time by which a rewind/immediate command ; must be completed $DEF UCB$L_UNLOAD_TIME .BLKL 1 ; Time by which a unload command ; must be completed $DEF UCB$B_BUSY_RETRY .BLKB 1 ; Retry count for BUSY during send $DEF UCB$B_SENSE_KEY .BLKB 1 ; Saved extended sense key (obsolete) $DEF UCB$B_SCSI_VERSION .BLKB 1 ; SCSI version from INQUIRY $DEF UCB$B_LUN .BLKB 1 ; Logical unit number (LUN) $DEF UCB$B_COMP_STATE .BLKB 1 ; saved data compaction state for ; SETUP_COMPACTION routine $DEF UCB$B_SAVED_COMP .BLKB 1 ; Current compaction state before ; CHECK_COMPACTION_SUPPORT called $DEF UCB$W_MK_DENSITY .BLKW 1 ; Saved 9-track density $DEF UCB$L_8MM_CHK .BLKL 1 ; 8MM $ COPY check-in-progress flag $DEF UCB$L_DISABLE_DDR .BLKL 1 ; Non-zero disables DDR ; (DEFAULT IS DISABLED!) $DEF UCB$L_ERROR_TYPE .BLKL 1 ; Error type used by LOG_ERROR $DEF UCB$L_VMS_STATUS .BLKL 1 ; VMS status used by LOG_ERROR $DEF UCB$L_SAV_SEND_STATUS .BLKL 1 ; Status returned by SEND_COMMAND $DEF UCB$L_INITMO .BLKL 1 ; Unit init timeout value MK_INIT_TIMEOUT = 60 ; Init timeout value = 60 seconds NUM_LONGWORDS_DIAGNOSE = 6 ; UCB area used by IO_DIAGNOSE $DEF UCB$PS_DIAGNOSE .BLKL NUM_LONGWORDS_DIAGNOSE $DEF UCB$K_MK_UCBLEN ; Length of extended UCB $DEFEND UCB ; End of UCB definitions .SYMBOL_ALIGNMENT NONE .PAGE .SBTTL Errorlog packet formats ;+ ; Following are the definitions for class driver errorlog packets. Each packet ; has a section common for all error types followed by an error-specific section. ;- $DEFINI ERROR_PACKETS . = EMB$L_DV_REGSAV ; Start of area to dump error info $DEF ERR$LW_CNT .BLKL 1 ; Count of number of LWs that follow $DEF ERR$REVISION .BLKB 1 ; Revision level $DEF ERR$HW_REV .BLKL 1 ; Hardware revision $DEF ERR$TYPE .BLKB 1 ; Error type $DEF ERR$SCSI_ID .BLKB 1 ; SCSI ID $DEF ERR$SCSI_LUN .BLKB 1 ; SCSI logical unit $DEF ERR$SCSI_SUBLUN .BLKB 1 ; SCSI sub-logical unit $DEF ERR$PORT_STATUS .BLKL 1 ; Port status code $DEF ERR$CMD_LEN .BLKB 1 ; SCSI command length field $DEF ERR$SCSI_STS .BLKB 1 ; SCSI status byte $DEF ERR$ADDIT_LEN .BLKB 1 ; Additional length field $DEF ERR$K_STANDARD_LENGTH ; Standard length of error packet ; Now define packets that have one or more of the variable length fields ; filled in. These fields consist of a byte count followed by n bytes of ; data. In the standard packet defined above, the byte count field would ; contain a zero for each possible variable length field. The list of variable ; length fields is: ; ; o SCSI command data (up to 12 bytes) ; o Additional data which depends upon the error type $DEF ERR$CMD_BYTES .BLKB 12 ; Maximum possible command bytes $DEF ERR$K_COMMAND_LENGTH ; Length of packet containing SCSI command $DEF ERR$INQUIRY_DATA .BLKB 36 ; Inquiry data $DEF ERR$K_INQUIRY_LENGTH ; Length of packet containing INQUIRY data .=ERR$K_COMMAND_LENGTH $DEF ERR$EXTND_SENSE_DATA .BLKB 18 ; Extended sense data $DEF ERR$K_EXTND_SENSE_LENGTH ; Length of packet containing extended ; sense data .=ERR$K_COMMAND_LENGTH $DEF ERR$MODE_SENSE_DATA .BLKB 150 ; Mode sense data $DEF ERR$K_MODE_SENSE_LENGTH ; Length of packet containing mode ; sense data .=ERR$K_COMMAND_LENGTH $DEF ERR$REASSIGN_BLOCK_DATA .BLKB 8 ; Reassign block data $DEF ERR$K_REASSIGN_BLOCK_LENGTH ; Length of packet containing reassign ; block data .=ERR$K_COMMAND_LENGTH $DEF ERR$DIAGNOSTIC_DATA .BLKB 18 ; Received diagnostic data $DEF ERR$K_DIAGNOSTIC_DATA_LENGTH ; Length of packet containing received ; diagnostic data $DEFEND ERROR_PACKETS .PAGE .SBTTL + .SBTTL + MACRO DEFINITIONS .SBTTL + .SBTTL MEDIA - MSCP media identifier to VMS device type conversion ;+ ; MEDIA - modified version of the macro used in DUTUSUBS.MAR (DUDRIVER) ; ; Functional description: ; ; This macro produces one entry in the MSCP media identifier to VMS ; device type conversion table. ; ; Parameters: ; ; dd the two character prefered device controller name ( the DD ; part of DDCn ) ; devnam the hardware device name ( e.g. RA81 ) ; dtname if DT$_'devnam' is not a legal VMS device type, this parameter ; gives the correct VMS device type for the device ( should be ; used only when DT$_'devnam' is not correct ) ;- .MACRO MEDIA DD, DEVNAM, DTNAME $$BEGIN$$=-1 $$MEDIA$$=0 $$S$$=27 .IRPC $$L$$,
$$TEMP$$ = ^A/$$L$$/ - ^X40 .IF GT $$TEMP$$ $$MEDIA$$ = $$MEDIA$$ + <$$TEMP$$ @ $$S$$> .ENDC $$S$$ = $$S$$ - 5 .ENDR .IRPC $$L$$, .IF GE <$$S$$ - 7> $$TEMP$$ = ^A/$$L$$/ - ^X40 .IF GT $$TEMP$$ $$MEDIA$$ = $$MEDIA$$ + <$$TEMP$$ @ $$S$$> .IF_FALSE .IIF LT $$BEGIN$$, $$BEGIN$$ = <17-$$S$$>/5 .ENDC $$S$$ = $$S$$ - 5 .ENDC .ENDR .IIF LT $$BEGIN$$, $$BEGIN$$ = 3 $$N$$ = %EXTRACT( $$BEGIN$$, 3, DEVNAM ) $$MEDIA$$ = $$MEDIA$$ + $$N$$ .LONG $$MEDIA$$ .ENDM MEDIA .PAGE .SBTTL SENSE_KEY - Build sense key to VMS status code translation table ;+ ; SENSE_KEY ; ; This macro is used to build a translation table of SCSI to VMS status codes. ; Each time extended sense information is returned by the target, the sense ; key is translated to a VMS status code using this table. The status code ; will be located using the SCSI sense key as an index. ; ; ;- .MACRO SENSE_KEY, VMS_STATUS .LONG SS$_'VMS_STATUS' .ENDM SENSE_KEY .PAGE .SBTTL LOG_ERROR - Log a SCSI tape class driver error ;+ ; LOG_ERROR ; ; This macro logs a SCSI tape class driver error. The error type and VMS status ; code are placed in R7 and R8 respectively, and the LOG_ERROR routine is ; called, which does most of the work. ;- .MACRO LOG_ERROR,TYPE,VMS_STATUS,UCB=R3 PUSHL R5 ; Save regs .IF DIF UCB,R5 MOVL UCB,R5 ; Get UCB address .ENDC MOVL #SCSI$C_'TYPE',- ; Get error code UCB$L_ERROR_TYPE(R5) MOVL VMS_STATUS,- ; And VMS status code UCB$L_VMS_STATUS(R5) BSBW LOG_ERROR ; Write an errorlog entry POPL R5 ; Restore regs .ENDM LOG_ERROR .MACRO SETUP_CMD cmd=r2,ucb=R3,pdt=R4,scdrp_addr=R5 PUSHL 'scdrp_addr' ; PUSHL 'pdt' ; PUSHL 'ucb' ; PUSHL 'cmd' CALLS #4,SETUP_CMD ; Setup the SCSI command .ENDM SETUP_CMD .MACRO SEND_COMMAND_ORDERED ucb=R3,pdt=R4,scdrp_addr=R5 MOVL #SCDRP$K_QCHAR_ORDERED,- ; Send this as an ordered command. SCDRP$IS_QUEUE_CHAR(scdrp_addr) PUSHL 'scdrp_addr' ; PUSHL 'pdt' ; PUSHL 'ucb' ; CALLS #3,SEND_COMMAND ; Send the SCSI command .ENDM SEND_COMMAND_ORDERED .MACRO CLEANUP_CMD pdt=R4,scdrp_addr=R5 PUSHR #^M ; Save R0, R1 PUSHL 'scdrp_addr' ; PUSHL 'pdt' ; CALLS #2,CLEANUP_CMD ; Cleanup the SCSI command POPR #^M ; Restore R0, R1 .ENDM CLEANUP_CMD .PAGE .SBTTL SCSI_ERROR_CODES - Define SCSI error codes, build error length table ;+ ; SCSI_ERROR_CODES ; ; This macro defines the class driver error codes and generates a table of ; error lengths used during errorlogging to determine the size of the errorlog ; packet to allocate. The table is indexed by the error type to find the ; length of the packet which is stored as a word. ;- .MACRO SCSI_ERROR_CODES, ERROR_LIST $$CODE_VALUE = 1 .MACRO SCSI_ERROR_CODES1 CODE, LEN SCSI$C_'CODE' = $$CODE_VALUE $$CODE_VALUE = $$CODE_VALUE + 1 .WORD ERR$K_'LEN' .ENDM SCSI_ERROR_CODES1 .IRP LIST_ENTRY, SCSI_ERROR_CODES1 LIST_ENTRY .ENDR .ENDM SCSI_ERROR_CODES .SBTTL DISABLE_ERRLOG - Temporarily disable errorlogging .SBTTL REENABLE_ERRLOG - Reenable errorlogging ;+ ; DISABLE_ERRLOG ; REENABLE_ERRLOG ; ; This macros are used to disable and reenable errorlogging respectively. ; The DISABL_ERRLOG flag in the UCB is used to temporarily disable errorlogging ; when the class driver prepares to do something which is likely to cause an ; error that should be supressed. For example, when checking to see if a ; device supports COMPACTION, we don;t want a failed MODE_SELECT to generate ; an error log. ; Since the disabling of errorlogging can be nested, the old value of the ; DISABL_ERRORLOG flag is saved in the stack. .MACRO DISABLE_ERRLOG PUSHL UCB$L_MK_FLAGS(R3) ; Save current flags value ASSUME UCB$V_DISABL_ERRLOG LT 8 BISB #UCB$M_DISABL_ERRLOG,- ; Temporarily disable errorlogging UCB$L_MK_FLAGS(R3) ; .ENDM DISABLE_ERRLOG .MACRO REENABLE_ERRLOG POPL UCB$L_MK_FLAGS(R3) ; Reenable errorlogging .ENDM REENABLE_ERRLOG .PAGE .SBTTL MK_ALLOC_SCDRP - Allocate an SCDRP ;+ ; MK_ALLOC_SCDRP ; ; This macro is used to allocate an SCDRP on the kernel process stack. ; ; INPUTS: ; R3 - UCB address ; ; OUTPUTS: ; R5 - SCDRP address ; R0 - destroyed ; SCDRP_ALLO_LEN = <<&^C7> + 8> .MACRO MK_ALLOC_SCDRP SUBL #SCDRP_ALLO_LEN,SP ; Allocate SCDRP on the stack ADDL3 #7,SP,R5 ; R5 = SCDRP address, quadword BICL #7,R5 ; aligned .SET_REGISTERS ALIGNED= BSBW INIT_SCDRP ; Initialize allocated SCDRP .ENDM MK_ALLOC_SCDRP .PAGE .SBTTL MK_DEACTIVATE_SCDRP - Deactivate an SCDRP ;+ ; MK_DEACTIVATE_SCDRP ; ; This macro deactivates an SCDRP by clearing the appropriate UCB field. ; A sanity check is performed to ensure that any map registers for this ; command have been deallocated. By default, deallocation of the SCDRP ; will occur implicitly via kernel process termination, although ; explicit deallocation may be requested by specifying CLRSTK=YES. ; ; INPUTS: ; R3 - UCB address ; R5 - SCDRP address ; ; OUTPUTS: ; UCB$L_SCDRP - Initialized ; .MACRO MK_DEACTIVATE_SCDRP,CLRSTK=NO,?L1,?L2 .IF DEFINED DEBUG TSTW SCDRP$W_MAPREG(R5) ; Hanging on to any mapping regs? BNEQ L1 ; Branch if so TSTW SCDRP$W_NUMREG(R5) ; Hanging on to any mapping regs? BEQL L2 ; Branch if not L1: BUG_CHECK INCONSTATE,FATAL ; Should not deactivate an SCDRP .ENDC L2: CLRL UCB$L_SCDRP(R3) ; No active SCDRP for this UCB .IF IDN , ; If explicit deallocation is required ADDL #SCDRP_ALLO_LEN,SP ; Clear SCDRP off the stack .ENDC .ENDM MK_DEACTIVATE_SCDRP .PAGE .SBTTL SCSI_CMD - Define a SCSI command packet ;+ ; SCSI_CMD ; ; This macro defines the contents of a SCSI command packet. Each SCSI command ; can have associated with it a DMA buffer used during the DATAIN/DATAOUT bus ; phases. A DMA length of zero indicates there is no DATA(IN/OUT) phase ; associated with this command (except in the case of a read/write SCSI command ; which is handled specially. The SETUP_CMD routine uses this information in ; preparing to send a SCSI command. The macro generates a label and the SCSI ; command information as follows: ; ; +-----------------------+ ; | SCSI cmd length | 1 byte ; +-----------------------+ ; | SCSI cmd bytes | n bytes ; +-----------------------+ ; |Timeout value (seconds)| 2 bytes ; +-----------------------+ ; | DMA buffer length | 2 bytes ; +-----------------------+ ; | DMA direction | 1 byte ; +-----------------------+ ; ; DMA direction is defined as: 0=write, 1=read. ;- .MACRO SCSI_CMD, NAME, CMD_BYTES, DMA_LEN=0, DMA_DIR=READ, TIMEOUT=30 .ALIGN QUAD CMD_'NAME':: $$$BYTE_COUNT=0 .IRP CMD_BYTE, $$$BYTE_COUNT = $$$BYTE_COUNT + 1 .IIF EQ $$$BYTE_COUNT-1, SCSI$C_'NAME' = CMD_BYTE ; Define opcode .ENDR .BYTE $$$BYTE_COUNT .IRP CMD_BYTE, .BYTE CMD_BYTE .ENDR .WORD TIMEOUT .WORD DMA_LEN $$$DIRECTION = 0 .IIF IDN DMA_DIR, READ, $$$DIRECTION = 1 .BYTE $$$DIRECTION .IIF IDN NAME,MODE_SELECT_TMP, MODE_SEL_TMP_LEN = .-CMD_'NAME' .ENDM SCSI_CMD .PAGE .SBTTL IF_TZ30 - Branch if device a TZ30 .SBTTL IF_TK50 - Branch if device is a TZK50 .SBTTL IFNOT_TZ30 - Branch if device is not a TZ300 .SBTTL IFNOT_TK50 - Branch if device is not a TZK50 .SBTTL IF_TK - Branch if device is a TZK50 or TZ30 .SBTTL IFNOT_TK - Branch if device is not a TZK50 or TZ30 .SBTTL IF_TSZ05 - Branch if device is a TSZ05 .SBTTL IFNOT_TSZ05 - Branch if device is not a TSZ05 .SBTTL IF_TSZ07 - Branch if device is a TSZ07 .SBTTL IFNOT_TSZ07 - Branch if device is not a TSZ07 .SBTTL IF_TZK10 - Branch if device is a TZK10 .SBTTL IFNOT_TZK10 - Branch if device is not a TZK10 .SBTTL IF_8MM - Branch if device is an 8mm device .SBTTL IFNOT_8MM - Branch if device is not an 8mm device .SBTTL IF_TZK11 - Branch if device is a TZK11 .SBTTL IF_TKZ09 - Branch if device is a TKZ09 .SBTTL IF_TKZ60 - Branch if device is a TKZ60 .SBTTL IFNOT_TKZ60 - Branch if device is not a TKZ60 ;- ; IF_TZ30 ; IF_TK50 ; IFNOT_TZ30 ; IF_TK ; IFNOT_TK ; IF_TSZ05 ; IFNOT_TSZ05 ; IF_TSZ07 ; IFNOT_TSZ07 ; IF_TZK10 ; IFNOT_TZK10 ; IF_TZK11 ; IF_TKZ09 ; IF_TKZ60 ; IFNOT_TKZ60 ; ; These macros are used for device-dependent dispatching. ;- .MACRO IF_TZ30, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TZ30? #DT$_TZ30 ; BEQL LABEL ; Branch if so .ENDM IF_TZ30 .MACRO IF_TK50, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TK50? #DT$_TK50 ; BEQL LABEL ; Branch if so .ENDM IF_TK50 .MACRO IFNOT_TK50, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TK50? #DT$_TK50 ; BNEQ LABEL ; Branch if not .ENDM IFNOT_TK50 .MACRO IFNOT_TZ30, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TZ30? #DT$_TZ30 ; BNEQ LABEL ; Branch if not .ENDM IFNOT_TZ30 .MACRO IF_TK, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TZ30? #DT$_TZ30 ; BEQL LABEL ; Branch if so CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TK50? #DT$_TK50 ; BEQL LABEL ; Branch if so .ENDM IF_TK .MACRO IFNOT_TK, LABEL, UCB=R3, ?L CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TZ30? #DT$_TZ30 ; BEQL L ; Branch if so CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TK50? #DT$_TK50 ; BNEQ LABEL ; Branch if not L: .ENDM IFNOT_TK .MACRO IF_TSZ05, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TSZ05? #DT$_TSZ05 ; BEQL LABEL ; Branch if so .ENDM IF_TSZ05 .MACRO IFNOT_TSZ05, LABEL, UCB=R3, CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TSZ05? #DT$_TSZ05 ; BNEQ LABEL ; Branch if not .ENDM IFNOT_TSZ05 .MACRO IF_TSZ07, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TSZ07? #DT$_TSZ07 ; BEQL LABEL ; Branch if so .ENDM IF_TSZ07 .MACRO IFNOT_TSZ07, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TSZ07? #DT$_TSZ07 ; BNEQ LABEL ; Branch if not .ENDM IFNOT_TSZ07 .MACRO IF_TZK10, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TZK10 ? #DT$_TZK10 ; for retensioning BEQL LABEL ; Branch if yes .ENDM IF_TZK10 .MACRO IFNOT_TZK10, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TZK10 ? #DT$_TZK10 ; for retensioning BNEQ LABEL ; Branch if not .ENDM IFNOT_TZK10 .MACRO IF_TZK11, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TZK11 ? #DT$_TZK11 ; for retensioning BEQL LABEL ; Branch if yes .ENDM IF_TZK11 .MACRO IF_TKZ09, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TKZ09 ? #DT$_TKZ09 ; BEQL LABEL ; Branch if yes .ENDM IF_TKZ09 .MACRO IF_TKZ60, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TKZ60 ? #DT$_TKZ60 ; BEQL LABEL ; Branch if yes .ENDM IF_TKZ60 .MACRO IFNOT_TKZ60, LABEL, UCB=R3 CMPB UCB$B_DEVTYPE(UCB),- ; Is device a TKZ60 ? #DT$_TKZ60 ; BNEQ LABEL ; Branch if no .ENDM IFNOT_TKZ60 .MACRO IF_8MM, LABEL, UCB=R3 BITL #UCB$M_DEVICE_IS_8MM,- UCB$L_MK_FLAGS(UCB) ; Is device an 8mm tape BNEQ LABEL ; Branch if so .ENDM IF_8MM .MACRO IFNOT_8MM, LABEL, UCB=R3 BITL #UCB$M_DEVICE_IS_8MM,- UCB$L_MK_FLAGS(UCB) ; Is device an 8mm tape BEQL LABEL ; Branch if not .ENDM IFNOT_8MM ;+ ; $ARG_DEF - Define a Routine's Input Parameters. ;- .MACRO $ARG_DEF argument_list argument_offset = 4 .IRP argument, argument = argument_offset argument_offset = argument_offset + 4 .ENDR .ENDM $ARG_DEF .PAGE .SBTTL + .SBTTL + DRIVER TABLES .SBTTL + .SBTTL Driver prologue table ;+ ; Driver prologue table ; ; This table provides various information about the driver such as its name ; and length, and causes initialization of various fields in the I/O database ; when the driver is loaded. ;- DPTAB - ; DPT-creation macro STEP=2,- ; Driver is Step 2 ADAPTER=NULL,- ; Adapter type UCBSIZE=,- ; Length of UCB NAME=MKDRIVER,- ; Driver name SMP=YES,- ; Driver runs in SMP environment FLAGS= ; Don't fill in IDB$L_UCBLST DPT_STORE INIT ; Start of load ; initialization table DPT_STORE DDB,DDB$L_ACPD,L,<^A\MTA\> ; Default ACP name DPT_STORE UCB,UCB$L_MAXBCNT,L,MAX_BCNT ; Max byte count DPT_STORE UCB,UCB$B_FLCK,B,SPL$C_IOLOCK8 ; Device FORK LOCK DPT_STORE UCB,UCB$B_DIPL,B,22 ; Device interrupt IPL DPT_STORE UCB,UCB$L_DEVCHAR,L,<- ; Device characteristics DEV$M_FOD!- ; Files oriented DEV$M_DIR!- ; Directory structured DEV$M_AVL!- ; Available DEV$M_ELG!- ; Error logging enabled DEV$M_IDV!- ; Input device DEV$M_ODV!- ; Output device DEV$M_SDI!- ; Single directory device DEV$M_SQD> ; Random Access Device DPT_STORE UCB,UCB$L_DEVCHAR2,L,<- ; Device characteristics DEV$M_SCSI!- ; device is a SCSI device DEV$M_NNM> ; Prefix name with "node$" DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_TAPE ; Sample device class DPT_STORE UCB,UCB$B_DEVTYPE,B,- ; Device type (default) DT$_GENERIC_MK DPT_STORE UCB,UCB$W_DEVBUFSIZ,W,2048 ; Default buffer size DPT_STORE UCB,UCB$L_DEVDEPEND,W,- ; Default tape parameters DEF_TAPE_PARAMS ; Format=DEFAULT, Density=BLK_833 DPT_STORE UCB,UCB$L_ERTCNT,L,16 ; Error retry count DPT_STORE UCB,UCB$L_ERTMAX,L,16 ; Max error retry count DPT_STORE UCB,UCB$L_MK_FLAGS,L,0 ; Initialize flags field DPT_STORE UCB,UCB$L_ERR_MASK,L,0 ; Initialize error mask field DPT_STORE UCB,UCB$W_MK_DENSITY,W,- ; Initialize 9-track H/W MT$K_GCR_6250-2 ; density. DPT_STORE UCB,UCB$L_DISABLE_DDR,L,1 ; Non zero disables DDR DPT_STORE REINIT ; Start of reload ; initialization table DPT_STORE CRB,CRB$B_FLCK,B,IPL$_IOLOCK8 ; Initialize fork lock field DPT_STORE END ; End of initialization ; tables .PAGE .SBTTL Driver dispatch table ;+ ; Driver dispatch table ; ; This table defines the entry points into the driver. ;- DDTAB - ; DDT-creation macro DEVNAM=MK,- ; Name of device START=EXE_STD$KP_STARTIO,- ; Caller of Start I/O routine KP_STARTIO=MK_STARTIO,- ; Start I/O routine KP_STACK_SIZE=8192,- ; Size of kernel process stack KP_REG_MASK=KPREG$K_HLL_REG_MASK,- ; Kernel process reg save mask CTRLINIT=MK_CTRL_INIT,- ; Controller init routine UNITINIT=MK_UNIT_INIT,- ; Unit init routine FUNCTB=MK_FUNCTABLE,- ; FDT address CANCEL=MK_CANCEL,- ; Cancel I/O routine REGDMP=MK_REG_DUMP,- ; Register dump routine FAST_FDT=ACP_STD$FASTIO_BLOCK ; Fast-FDT routine address .SBTTL Function decision table ;+ ; Step 2 Function decision table ; ; This table lists the buffered QIO function codes and the action routines with their ; valid function codes. ;- FDT_INI MK_FUNCTABLE ; FDT for Driver FDT_BUF - ; Buffered I/O functions ; Mount volume FDT_64 <- ; Functions supporting 64-bit addresses AVAILABLE,- ; Available (rewind/nowait clear valid) DIAGNOSE,- ; Special pass-thru function DRVCLR,- ; Drive clear DSE,- ; Data security erase ERASETAPE,- ; Erase tape NOP,- ; No operation PACKACK,- ; Pack acknowledge READLBLK,- ; Read logical block forward READPBLK,- ; Read physical block forward READPRESET,- ; Read in preset READVBLK,- ; Read virtual block RECAL,- ; Recalibrate (rewind) REREADN,- ; Read next REREADP,- ; Read previous REWIND,- ; Rewind REWINDOFF,- ; Rewind and set offline SETCHAR,- ; Set characteristics SETMODE,- ; Set mode UNLOAD,- ; Unload volume WRITECHECK,- ; Write check forward WRITEOF,- ; Write end of file WRITELBLK,- ; Write logical block WRITEMARK,- ; Write tape mark WRITEPBLK,- ; Write physical block WRITERET,- ; Write retry WRITEVBLK> ; Write virtual block FDT_ACT ACP_STD$READBLK,- ; Read functions ; Read virtual block FDT_ACT ACP_STD$WRITEBLK,- ; Write functions ; Write virtual block FDT_ACT ACP_STD$ACCESS, ; Access & create file or directory FDT_ACT ACP_STD$DEACCESS, ; Deaccess file FDT_ACT ACP_STD$MODIFY,- ; ; Modify file attributes FDT_ACT ACP_STD$MOUNT, ; Mount volume FDT_ACT MT_STD$CHECK_ACCESS,- ; Magtape check access funcitons ; Write end of file FDT_ACT EXE_STD$ZEROPARM,- ; Zero parameter functions ; Available (rewind/nowait clear valid) FDT_ACT EXE_STD$ONEPARM,- ; One parameter functions ; Skip files FDT_ACT MK_SENSEMODE,- ; Sense tape characteristics ; Sense mode FDT_ACT EXE_STD$SETMODE,- ; Set tape characteristics ; FDT_ACT MK_DIAGNOSE,<- ; Special pass-through function DIAGNOSE> ; .PAGE ; TQE_WAIT data SECOND = 10000000 ; Number of clock ticks in a second ONE_SECOND: .LONG < 1*SECOND>,0 ; 1 second TWO_SECONDS: .LONG < 2*SECOND>,0 ; 2 seconds THIRTY_SECONDS: .LONG <30*SECOND>,0 ; 30 seconds SIXTY_SECONDS: .LONG <60*SECOND>,0 ; 60 seconds POLL_INTERVAL: .LONG ,0 .PAGE .SBTTL SCSI_DEV_TYPES - Build SCSI device table ;+ ; SCSI_DEV_TYPES ; ; This macro builds a table of pre-defined SCSI device types. During unit ; initialization, an inquiry command is sent to the target which returns ; 8 bytes of ID string. The table is then scanned for a matching ID. If one ; is found, information for that entry is copied into the UCB, including the ; device type, media ID, disconnect/synchronous flags, and various timeout ; values. If no matching entry is found, the device is assumed to be a ; "generic" SCSI disk, and the entry for generic devices is used. Each entry ; in the device type table has the following format: ; +-----------------------+ ; | VMS device type | 1 byte ; +-----------------------+ ; | Density code | 1 byte ; +-----------------------+ ; | Vendor-unique info | 10 bytes ; +-----------------------+ ; | ID string | 8 bytes ; +-----------------------+ ; | Min revision level | 4 bytes ; +-----------------------+ ; | Media ID | 4 bytes ; +-----------------------+ ; | Loader info | 1 byte ; +-----------------------+ ; | Pad for alignment | 3 bytes ; +-----------------------+ ; ; ; The table is terminated with a VMS device code of 0. ;- $DEFINI SCSI_DEVICE_ENTRY $DEF DTYP_TYPE .BLKB 1 $DEF DTYP_DENSITY .BLKB 1 $DEF DTYP_VENDOR .BLKB 10 $DEF DTYP_ID_LOW .BLKL 1 $DEF DTYP_ID_HIGH .BLKL 1 $DEF DTYP_MINREV .BLKL 1 $DEF DTYP_MEDIA_ID .BLKL 1 $DEF DTYP_FLAGS .BLKL 1 ; $VIELD DTYP,0,<- ; ,- ; Bit 0 = loader support ,- ; Bit 1 = inhibit sync mode > ; Bit 2 = inhibit skip-by-file $DEF DTYP_TABLE_ENTRY_SIZE ; Size of SCSI Device Table Entry $DEFEND SCSI_DEVICE_ENTRY ASSUME DTYP_TABLE_ENTRY_SIZE EQ 32 .MACRO SCSI_DEV_TYPES, LIST .MACRO SCSI_DEV_TYPES1, ID_STRING, DEVICE_TYPE, MINIMUM_REVISION, - DENSITY, MODE_SEL_INFO, LOADER, SYNC_MODE, SKIPFILE .IF IDN , TZ30 TZ30_DEV_TYPE: .ENDC .IF IDN , TK50 TK50_DEV_TYPE: .ENDC .IF IDN , GENERIC GENERIC_DEV_TYPE: .ENDC ; Device type .BYTE DT$_'DEVICE_TYPE' ; Density code .BYTE MT$K_'DENSITY' ; Vendor-unique mode select data. This is a counted string of bytes with the ; first byte specifying the number of bytes that follow. The total field length, ; including the count, is 10 bytes. $$$COUNT = 0 .IRP MODE_SEL_BYTE, $$$COUNT = $$$COUNT + 1 .ENDR .IIF GT $$$COUNT-7, .ERROR ; - Illegal number of mode sense bytes .BYTE $$$COUNT .IRP MODE_SEL_BYTE, .BYTE MODE_SEL_BYTE .ENDR .REPT 9-$$$COUNT .BYTE 0 .ENDR ; 8 character product ID string, padded with spaces .NCHR $$$STRLEN, .IIF GT $$$STRLEN-8, .ERROR ;Illegal SCSI product ID: ID_STRING $$$PADCNT = 8-$$$STRLEN .ASCII /ID_STRING/ .REPT $$$PADCNT .ASCII / / .ENDR ; Minimum revision level. This field is compared to the revision field returned ; in the inquiry data. If the device is out of rev, an error is logged. .NCHR $$$MINREV, .IIF GT $$$MINREV-4, .ERROR ;Illegal minimum rev level: MINIMUM_REVISION .ASCII /MINIMUM_REVISION/ ; Media ID field .IF IDN DEVICE_TYPE,GENERIC_MK MEDIA , , DT$_GENERIC_MK ; Media value for generic MK device .IFF MEDIA , .ENDC ; Flags $$$FLAGS = 0 .IIF IDN LOADER, YES, $$$FLAGS = $$$FLAGS + DTYP$M_LOADER .IIF IDN SYNC_MODE, NO, $$$FLAGS = $$$FLAGS + DTYP$M_NO_SYNC_MODE .IIF IDN SKIPFILE, NO, $$$FLAGS = $$$FLAGS + DTYP$M_NO_SKIPFILE .BYTE $$$FLAGS ; Pad table entry for longword alignment .BLKB 3 .ENDM SCSI_DEV_TYPES1 .IRP ENTRY, SCSI_DEV_TYPES1 ENTRY .ENDR .ENDM SCSI_DEV_TYPES .PAGE .SBTTL SCSI device types table ;+ ; SCSI_DEVICE_TABLE ; ; This table is used to translate the product ID field from the inquiry data ; to a VMS device type and internal MK device type. The internal type code is ; used so that we can support multiple SCSI tape drives with a single VMS device ; code (generic_mk), yet distinguish between these drives, which may require ; different vendor-unique mode select data. The mode select data in this table ; is appended to the standard 4 byte parameter list header and 8 byte block ; descriptor. Several reserved entries are left in the table to allow for ; patching the driver to add support for new devices in the future. Note that ; because the TZ30 and TK50 don't conform to the standard inquiry data format, ; the GET_DEVICE_TYPE routine uses special case code to find their entries ; in the table. ; ; Clarification of the meaning of some fields: ; ; Sync mode: DEFAULT means that the default algorithms in the drivers ; should be used to determine the correct transfer mode. ; NO means that, no matter what the algorithms may determine, ; the device must be forced to async mode. ; ; Skipfile: DEFAULT means that the default algorithms in the drivers ; should be used to determine whether skipfile should be ; supported. NO means that, no matter what the algorithms may determine, ; the device must be forced to *not* skip by filemarks. ; ; Note: Any new devices added to this table should be assigned a VMS dev type ; of GENERIC_MK in order to avoid the need to define a DT$ symbol in Starlet. ;- SCSI_DEVICE_TABLE: .list meb SCSI_DEV_TYPES <- ; ; ID string VMS dev type Min Rev Density Mode select info Loader Sync mode Skipfile ; --------- ------------ ------- ------- ---------------- ------ --------- -------- ; <, TZ30, <0701>, BLK_833, <1, <^X4F>>, NO, DEFAULT, DEFAULT>,- <, TK50, <2D05>, BLK_833, <1, <^X47>>, NO, DEFAULT, DEFAULT>,- <, TLZ04, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, TLZ04, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, TLZ04, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, TZK10, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <<0-STD1-0>, TSZ05, < >, PE_1600, <>, NO, DEFAULT, DEFAULT>,- <, TSZ05, < >, PE_1600, <>, NO, DEFAULT, NO>,- <, TSZ07, < >, GCR_6250, <>, NO, DEFAULT, NO>,- <, TZK10, < >, DEFAULT, <>, NO, DEFAULT, NO>> SCSI_DEV_TYPES <- ; ; ID string VMS dev type Min Rev Density Mode select info Loader Sync mode Skipfile ; --------- ------------ ------- ------- ---------------- ------ --------- -------- ; <, TZ85, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, TZ86, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, TZ87, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, TLZ06, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, TKZ60, < >, DEFAULT, <>, NO, DEFAULT, NO>,- <, TZK11, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, TKZ09, < >, DEFAULT, <>, NO, DEFAULT, NO>> SCSI_DEV_TYPES <- <, GENERIC_MK, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, GENERIC_MK, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, GENERIC_MK, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, GENERIC_MK, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, GENERIC_MK, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>> SCSI_DEV_TYPES <- ; ; ID string VMS dev type Min Rev Density Mode select info Loader Sync mode Skipfile ; --------- ------------ ------- ------- ---------------- ------ --------- -------- ; <, TLZ06, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TKZ60, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TZ85, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TZ86, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TZ87, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, GENERIC_MK, < >, DEFAULT, <<^X22>>, NO, DEFAULT, DEFAULT>,- <, GENERIC_MK, < >, DEFAULT, <<^X22>>, NO, DEFAULT, DEFAULT>> SCSI_DEV_TYPES <- <, HST00, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, HST01, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TLZ07, < >, DEFAULT, <>, NO, DEFAULT, DEFAULT>,- <, TLZ07, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TZ88, < >, DEFAULT, <> NO, DEFAULT, DEFAULT>,- <, TZ88, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TZ88, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>> SCSI_DEV_TYPES <- <, TZ89, < >, DEFAULT, <> NO, DEFAULT, DEFAULT>,- <, TZ89, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TZ89, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TZ87, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TL810, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>,- <, TL820, < >, DEFAULT, <>, YES, DEFAULT, DEFAULT>> .BYTE 0 ; End of table .nlist meb .PAGE .SBTTL SCSI command definition tables SCSI_CMD - NAME = TEST_UNIT_READY,- CMD_BYTES = <0, 0, 0, 0, 0, 0> SCSI_CMD - NAME = REQUEST_SENSE,- CMD_BYTES = <3, 0, 0, 0, , 0>,- DMA_LEN = REQSNS_SIZE,- DMA_DIR = READ SCSI_CMD - NAME = READ,- CMD_BYTES = <8, 0, 0, 0, 0, 0>,- DMA_LEN = -1,- TIMEOUT=600 SCSI_CMD - NAME = WRITE,- CMD_BYTES = <10, 0, 0, 0, 0, 0>,- DMA_LEN = -1,- TIMEOUT=600 SCSI_CMD - NAME = READ_8MM,- ;Special 8MM READ CMD_BYTES = <8, 2, 0, 0, 0, 0>,- DMA_LEN = 80,- TIMEOUT=600 SCSI_CMD - ;Special 8MM WRITE NAME = WRITE_8MM,- CMD_BYTES = <10, 0, 0, 0, 0, 0>,- TIMEOUT=600 SCSI_CMD - NAME = INQUIRY,- CMD_BYTES = <18 , 0, 0, 0, 36, 0>,- DMA_LEN = 36,- DMA_DIR = READ SCSI_CMD - NAME = MODE_SELECT,- CMD_BYTES = <21 , <^X10>, 0, 0, 12, 0>,- DMA_LEN = 12,- DMA_DIR = WRITE,- TIMEOUT = 600 SCSI_CMD - NAME = MODE_SELECT_TMP,- CMD_BYTES = <21, <^X10>, 0, 0, 12, 0>,- DMA_LEN = 12,- DMA_DIR = WRITE,- TIMEOUT = 600 SCSI_CMD - NAME = MODE_SELECT_10,- CMD_BYTES = <85, <^X10>, 0,0,0,0,0, 0,12, 0>,- DMA_LEN = 12,- DMA_DIR = WRITE,- TIMEOUT = 600 SCSI_CMD - NAME = MODE_SENSE,- CMD_BYTES = <26, 0, 0, 0, 100, 0>,- DMA_LEN = 100,- DMA_DIR = READ,- TIMEOUT = 600 SCSI_CMD - NAME = MODE_SENSE_10,- CMD_BYTES = <90, 0, 0, 0,0,0,0, <^X04>,<^X00>,0>,- DMA_LEN = 1024,- DMA_DIR = READ,- TIMEOUT = 600 SCSI_CMD - NAME = MODE_SENSE_COMP,- ; get page ^X10 CMD_BYTES = <26, 0, <^X10>, 0, 12+16, 0>,- ; for compaction DMA_LEN = 12+16,- DMA_DIR = READ,- TIMEOUT = 600 SCSI_CMD - NAME = RECEIVE_DIAG,- CMD_BYTES = <28, 0, 0, 6, 0, 0>,- DMA_LEN = 6,- DMA_DIR = READ,- TIMEOUT = 600 SCSI_CMD - NAME = SEND_DIAG,- CMD_BYTES = <29, 0, 0, 0, 0, 0>,- DMA_LEN = 512,- DMA_DIR = WRITE SCSI_CMD - NAME = ERASE,- CMD_BYTES = <25, 1, 0, 0, 0, 0>,- TIMEOUT = 5*60*60 SCSI_CMD - NAME = REWIND,- CMD_BYTES = <1, 0, 0, 0, 0, 0>,- TIMEOUT=600 SCSI_CMD - ;SCSI LOAD Command with NAME = RETENSION,- ;retension set for QIC CMD_BYTES = <27, 1, 0, 0, 3, 0>,- ;tape drives... TIMEOUT=600 ; SCSI_CMD - NAME = UNLOAD,- CMD_BYTES = <27, 1, 0, 0, 0, 0>,- TIMEOUT=600 SCSI_CMD - NAME = SPACE,- CMD_BYTES = <17, 0, 0, 0, 0, 0>,- TIMEOUT=5*60*60 SCSI_CMD - NAME = WRITE_FILEMARKS,- CMD_BYTES = <16, 0, 0, 0, 0, 0>,- TIMEOUT=600 SCSI_CMD - NAME = READ_POSITION,- CMD_BYTES = <<^X34>, 0, 0, 0, 0, 0, 0, 0, 0, 0>,- DMA_LEN = 20,- DMA_DIR = READ,- TIMEOUT=600 .PAGE ; Descriptors for mode page fields, used by MODE SENSE operations. .MACRO MODE_FIELD_DESC PAGE,NAME,BOFF,BIT_OFFSET,BIT_SIZE,FLAGS,DESIRED 'PAGE'_'NAME'_DESC = . - DESCRIPTOR_BASE ; Offset from base .LONG 'BOFF' ; Byte offset in page .LONG 'BIT_OFFSET' ; Bit offset within byte .LONG 'BIT_SIZE' ; Size of field in bits .LONG 'FLAGS' ; Flag bits .QUAD 'DESIRED' ; Desired value .BLKL 2 ; Actual value .BLKL 1 ; Difference reason .BLKL 1 ; Reserved bits .ENDM MODE_FIELD_DESC .ALIGN LONG DESCRIPTOR_BASE = . ; Descriptors for use by Mode_Sense routine VENDOR_UNIQUE_PAGE_DESC = . - DESCRIPTOR_BASE MODE_FIELD_DESC - PAGE=VENDOR_UNIQUE,- NAME=DENS,- BOFF=MODE_DESC$C_DENS_BOFF,- BIT_OFFSET=0,- BIT_SIZE=8 MODE_FIELD_DESC - PAGE=VENDOR_UNIQUE,- NAME=BDLEN,- BOFF=MODE_DESC$C_BDLEN_BOFF,- BIT_OFFSET=0,- BIT_SIZE=8 MODE_FIELD_DESC - PAGE=VENDOR_UNIQUE,- NAME=DEVSPC,- BOFF=MODE_DESC$C_DEVPAR_BOFF,- BIT_OFFSET=0,- BIT_SIZE=8,- FLAGS= ; Descriptors for use by Setup_Compaction routine DEV_CONFIG_PAGE_DESC = . - DESCRIPTOR_BASE MODE_FIELD_DESC - PAGE=DEV_CONFIG,- NAME=SEL_DATA_COMP,- BOFF=14,- BIT_OFFSET=0,- BIT_SIZE=1,- FLAGS= MODE_FIELD_DESC - PAGE=DEV_CONFIG,- NAME=DEVSPC,- BOFF=MODE_DESC$C_DEVPAR_BOFF,- BIT_OFFSET=0,- BIT_SIZE=8,- DESIRED=SCSI_MSEL$M_BUF,- FLAGS= MODE_FIELD_DESC - PAGE=DEV_CONFIG,- NAME=DENS,- BOFF=MODE_DESC$C_DENS_BOFF,- BIT_OFFSET=0,- BIT_SIZE=8,- DESIRED=0,- FLAGS= ; Descriptors for use by Mode_Select routine VENDOR_UNIQUE_SEL_DESC = . - DESCRIPTOR_BASE MODE_FIELD_DESC - PAGE=VENDOR_UNIQUE_SEL,- NAME=PARAMS,- BOFF=0,- BIT_OFFSET=0,- BIT_SIZE=0,- FLAGS= BASIC_SELECT_DESC = . - DESCRIPTOR_BASE MODE_FIELD_DESC - PAGE=VENDOR_UNIQUE_SEL,- NAME=DEVSPC,- BOFF=MODE_DESC$C_DEVPAR_BOFF,- BIT_OFFSET=0,- BIT_SIZE=8,- DESIRED=SCSI_MSEL$M_BUF,- FLAGS= MODE_FIELD_DESC - PAGE=VENDOR_UNIQUE_SEL,- NAME=DENS,- BOFF=MODE_DESC$C_DENS_BOFF,- BIT_OFFSET=0,- BIT_SIZE=8,- DESIRED=0,- FLAGS= DESCRIPTOR_SIZE = . - DESCRIPTOR_BASE .PAGE .SBTTL Sense key to VMS status translation table ;+ ; SENSE_KEY_TABLE ; ; This table is used to translate SCSI extended sense keys to VMS status codes. ; Each entry contains a longword; its low word is VMS status and its high word ; is 0. The table is indexed by sense key value. ; - SENSE_KEY_TABLE: ; VMS status ; SCSI sense key ; ---------- ; ---------- SENSE_KEY NORMAL ; NO_SENSE SENSE_KEY NORMAL ; RECOVERED_ERROR SENSE_KEY DEVOFFLINE ; NOT_READY SENSE_KEY PARITY ; MEDIUM_ERROR SENSE_KEY DRVERR ; HARDWARE_ERROR SENSE_KEY DRVERR ; ILLEGAL_REQUEST SENSE_KEY MEDOFL ; UNIT_ATTENTION SENSE_KEY WRITLCK ; DATA_PROTECT SENSE_KEY OPINCOMPL ; BLANK_CHECK SENSE_KEY DRVERR ; VENDOR_UNIQUE SENSE_KEY DRVERR ; COPY_ABORTED SENSE_KEY DRVERR ; ABORTED_COMMAND SENSE_KEY NORMAL ; EQUAL SENSE_KEY DRVERR ; VOLUME_OVERFLOW SENSE_KEY DATACHECK ; MISCOMPARE SENSE_KEY DRVERR ; RESERVED .PAGE .SBTTL SCSI error length table ;+ ; SCSI_ERROR_LEN_TAB ; ; This table is indexed by the SCSI error type and specifies the length of ; the errorlog packet. ;- SCSI_ERROR_LEN_TAB: SCSI_ERROR_CODES <- ,- ,- ,- ,- ,- ,- ,- > .PAGE .SBTTL + .SBTTL + DRIVER ENTRY POINTS .SBTTL + .SBTTL MK_CTRL_INIT - Controller initialization routine ;+ ; MK_CTRL_INIT ; ; This routine is called to perform controller-specific initialization and ; is called by the operating system in three places: ; ; - at system startup ; - during driver loading and reloading ; - during recovery from a power failure ; ; Currently this routine simply creates a fork thread to setup a trace buffer. ; ; STEP 2 INTERFACE ; ; int CTRLINIT (IDB *, DDB *, CRB *) ; ; OBSOLETE STEP 1 INPUTS: ; ; R5 - address of the IDB ; R8 - address of the CRB (channel request block) ; ; OBSOLETE STEP 1 OUTPUTS: ; R0 - Status ; R1-R3 - Destroyed ;- DRIVER_CODE MK_CTRL_INIT: $DRIVER_CTRLINIT_ENTRY FETCH=NO PRESERVE= .IF DEFINED DEBUG MOVL CTRLARG$_IDB(AP),R4 MOVL CTRLARG$_CRB(AP),R5 ; Copy CRB address FORK ROUTINE = SETUP_TRACE CONTINUE=10$ ; Fork using the CRB fork block, R3 and R4 are outputs 10$: .ENDC MOVL #SS$_NORMAL,R0 RET ; Return to caller .PAGE .SBTTL MK_UNIT_INIT - Unit initialization routine ;+ ; MK_UNIT_INIT ; ; This routine performs unit-specific initialization and is called for each ; tape found on the SCSI bus. A connection to the port driver is established, ; which lasts for the life of the system. All traffic to this SCSI device is ; directed over this connection. ; ; An inquiry command is sent to the target to determine the device type. ; In addition, several sanity checks are made on the inquiry data to determine ; if the device is valid. If so, the unit is placed online and any I/O queued ; to the device during initialization is started. ; ; STEP 2 INTERFACE ; ; int UNITINIT (IDB *, UCB *) ; ; OBSOLETE STEP 1 INPUTS: ; ; R5 - UCB address ; ; OBSOLETE STEP 1 OUTPUTS: ; ; R0-R5 - Destroyed ; All other registers preserved ;- MK_UNIT_INIT: ; Initialize unit ; Generate a .CALL_ENTRY mask and move args into standard registers $DRIVER_UNITINIT_ENTRY PRESERVE = BBC #UCB$V_POWER,- ; Branch if powerfail has not been UCB$L_STS(R5),2$ ; NOT been detected RET ; Otherwise, exit immediately ; Que the fork block and RET 2$: FORK ENVIRONMENT=CALL, CONTINUE=10$ ; fork then to to 10$ and set return val KP_ALLOCATE_KPB - ; Allocate kernel process block KPB=UCB$PS_UNITINIT_KPB(R5),- FLAGS=#KP$M_IO ; Specify deallocation at end of unit init BLBC R0,30$ ; Branch if error allocating KPB clrw ucb$l_devdepnd3(r5) ; initially set default density ops MOVL UCB$PS_UNITINIT_KPB(R5),- ; Save KPB address in UCB R2 MOVL R5,KPB$PS_UCB(R2) ; Save UCB address in KPB KP_START - ; Start the kernel process that does KPB=R2, - ; most of the unit init work ROUTINE=MK_KP_UNIT_INIT, - REGISTERS=#KPREG$K_HLL_REG_MASK RET ; Return from DK_UNIT_INIT ; ; here after for is queued. return success ; 10$: MOVL #SS$_NORMAL,R0 ; set return value to success RET ; and return 30$: BUG_CHECK INCONSTATE,FATAL ; Bugcheck ; The remainder of this routine runs as a kernel process. ; This is necessary to make SPI$ calls and access the port driver. ; ; The KP register save mask (above) saves all registers appropriate to a HLL ; driver. This permits port drivers to be written in a high-level language. ; The starting KP routine (call entry below) saves only the registers used ; by that routine. MK_KP_UNIT_INIT: .CALL_ENTRY - PRESERVE= MOVL 4(AP),R2 ; Pick up pointer to KPB MOVL KPB$PS_UCB(R2),R5 ; Restore UCB address ASSUME UCB$V_DISCONNECT LT 8 MOVB #UCB$M_DISCONNECT!- ; By default, assume the target device UCB$M_SYNCHRONOUS,- ; is capable of both disconnecting and UCB$L_MK_FLAGS(R5) ; synchronous operation BISL #UCB$M_ONLINE!- ; Set unit online and busy to allow I/O UCB$M_BSY,- ; to be queued UCB$L_STS(R5) ; MOVAL UCB$L_FLUSH_IOQFL(R5),R0; Initialize the queue used to flush MOVL R0,(R0) ; I/Os which are queued during unit MOVL R0,4(R0) ; init when unit init fails CLRL UCB$L_REWIND_TIME(R5) ; Indicate no rewind command has been ; recently CLRL UCB$L_UNLOAD_TIME(R5) ; Indicate no unload has been issued ; recently .IF DEFINED DEBUG CLRL R3 ; Prepare to call TRACE_QIO BSBW TRACE_QIO ; Trace this QIO (special case when ; called from UNIT INIT, R3 must be 0) .ENDC ; All SCSI tape unit numbers should be of the form "n0m" where n is the SCSI ; ID between 0 and 31 and m is the LUN between 0 and 7. Extract the ID from the ; LUN by dividing the unit number by 100. The quotient is the used as the ID ; while the remainder is the LUN. Note that the unit number contains three ; digits because early version of SCSI provided for sub-logical unit numbers. ; This feature has since been removed and the second digit in the unit number ; is not used. MOVL #SS$_BADPARAM,R0 ; Assume bad LUN or SUBLUN specified MOVZWL UCB$W_UNIT(R5),R1 ; Get device unit number CLRL R2 ; Prepare for extended divide EDIV #100,R1,R1,R2 ; Extract SCSI bus ID from LUN CMPL R1,#31 ; Valid SCSI ID (0 <= n <= 7)? BGTRU 20$ ; Branch if not CMPL R2,#7 ; Valid LUN (0 <= n <= 7)? BGTRU 20$ ; Branch if not CLRB UCB$B_LUN(R5) ; For Lun's bigger than 7 ASHL #16,R1,R1 ; Place SCSI ID in high-order word of R1 ASHL #16,R2,R2 ; Place LUN in high-order word of R2 MOVL UCB$L_DDB(R5),R0 ; Get DDB address SUBB3 #^A'A',- ; Translate controller letter to DDB$T_NAME+3(R0),R1 ; SCSI bus ID. .IIF NDF, DDB$V_PAC, DDB$V_PAC=1 ; X-14 BBC #DDB$V_PAC,- ; Using port allocation class? DDB$B_FLAGS(R0),6$ ; No, never mind SUBB3 #^A'A',- ; Yes, translate using original DDB$L_PORT_ID(R0),R1 ; controller letter. 6$: ADDL3 G^EXE$GL_ABSTIM,#MK_INIT_TIMEOUT,- ; Calculate and save init UCB$L_INITMO(R5) ; expiration time MOVL UCB$PS_UNITINIT_KPB(R5),R8 ; Get KPB address MOVL R1,KPB$PS_SCSI_PTR1(R8) ; Save SCSI IDs MOVL R2,KPB$PS_SCSI_PTR2(R8) ; Save LUN value 7$: SPI$CONNECT - ; Connect to the port driver PORT_STATE_CONTEXT=R5 ; Set callback context (UCB) for ; debugging purposes (CLUE SCSI) BLBS R0,10$ ; Branch if connect attempt succeeded CMPL UCB$L_INITMO(R5),- ; Has the timeout time passed? G^EXE$GL_ABSTIM BLEQU 20$ ; If so, set this unit OFFLINE KP_STALL_FORK_WAIT KPB=R8,- FKB=R5 ; Fork wait using UCB fork block MOVL KPB$PS_SCSI_PTR1(R8),R1 ; Restore SCSI IDs MOVL KPB$PS_SCSI_PTR2(R8),R2 ; Restore LUN value BRB 7$ ; Try connecting again 10$: CMPL R1,UCB$L_MAXBCNT(R5) ; For MAXBCNT, use minimum supported BGEQ 15$ ; value of port and class drivers MOVL R1,UCB$L_MAXBCNT(R5) ; Save maximum byte count in UCB 15$: MOVL R2,UCB$L_SCDT(R5) ; Save SCDT address MOVL R4,UCB$L_PDT(R5) ; Save PDT address PUSHL #NUM_LONGWORDS_DIAGNOSE ; Number of longwords in UCB ; reserved for IO$_DIAGNOSE PUSHAL UCB$PS_DIAGNOSE(R5) ; Start of DIAGNOSE longwords CALLS #2,DKMK$DIAGNOSE_INIT ; Initialize DIAGNOSE area BLBC R0,20$ ; Set offline if error PUSHL R5 ; Save working register MOVL R5,R3 ; Copy UCB address for MK_ALLOC_SCDRP MK_ALLOC_SCDRP ; Allocate an SCDRP off of the stack MOVL R8,SCDRP$PS_KPB(R5) ; Save KPB address in SCDRP SPI$INITIAL_PROCESSING ; Run the tolerant INQUIRY routine MK_DEACTIVATE_SCDRP CLRSTK=YES ; Free the SCDRP from the stack POPL R5 ; Restore working register BSBW SET_UNIT_ONLINE ; Go bring the unit online ; Notify the Media Manager (MME) that the device is online MOVL #MME$_NOTIFY_DEVICE, R0 ; load the event code. JSB G^MME$$DEV_EVENT ; invoke the MME call-out. RET ; Return to caller within KP services ; Connection failure. Log an error and set the unit offline. 20$: LOG_ERROR - ; Log a connection error TYPE=CONNECTION_ERROR,- ; VMS_STATUS=R0,- ; UCB=R5 ; BICL #UCB$M_ONLINE!- ; Set the unit offline and not busy UCB$M_BSY,- ; UCB$L_STS(R5) ; RET ; Return to caller within KP services .PAGE .SBTTL MK_SENSEMODE ;+ ; MK_SENSEMODE - SENSE DEVICE CHARACTERISTICS AND MODE ; ; This routine gets the device characteristics and returns them ; in the IOSB and optionally in a user specified buffer. ; If the user specified buffer is of the correct length, extended ; device characteristics will also be returned. ; ; If P1 is not specified, then IRP$L_SVAPTE in the I/O packet is ; cleared and only the device-dependent information will be returned ; in the second longword of the IOSB when the packet is queued via ; EXE$QIODRVPKT. ; ; If P1 is specified, then this routine allocates a system buffer ; and builds a buffer header using the user buffer address in P1 ; and the length as specified by P2. ; ; If P2 is not specified or is specified as a value other than ; 12, then a user buffer length of 8 bytes is assumed. The device ; class, type and buffer size will be returned in the user buffer ; along with the device-dependent information. ; ; If P2 is specified as 12, then the device class, type, buffer ; size, device-dependent information and extended device ; characteristics will be returned in the user buffer. ; ; STEP 2 INTERFACE: ; ; int FDT_ROUTINE (IRP *, PCB *, UCB *, CCB *) ; ; STEP 1 INPUT REGISTERS: ; ; R3 - I/O packet address ; R4 - Current pcb ; R5 - UCB address ; R6 - Assigned CCB address ; IRP$L_QIO_P1(R3) - Address of buffer ; IRP$L_QIO_P2(R3) - Length of buffer ; ; ; STEP 1 OUTPUT REGISTERS: ; ; R0 - Status of the operation ; R1,R2 - Destroyed ; All other registers preserved ; ; COMPLETION CODES: ; ; SS$_NORMAL - Successful ; SS$_ACCVIO - Buffer access violation ;- MK_SENSEMODE: .CALL_ENTRY PRESERVE= MOVL FDTARG$_IRP(AP), R3 ; Fetch IRP and UCB MOVL FDTARG$_UCB(AP), R5 CLRL IRP$L_SVAPTE(R3) ; Assume no user supplied buffer. MOVL IRP$L_QIO_P1(R3), R0 ; Get buffer address. BEQL 20$ ; Branch if none supplied. MOVZWL #8, R1 ; Assume buffer length of 8 bytes. CMPL #12,IRP$L_QIO_P2(R3) ; Length of 12 specified? BNEQ 10$ ; Branch if not. MOVZWL #12, R1 ; Set length in R1. 10$: CALL_READCHK ; Check buffer for write access. Macro RETs if R0 = SS$_FTD_COMPL ADDL3 #12, IRP$L_BCNT(R3), R1 ; Add 12 bytes for sys. overhd to size saved by CALL_READCHK in the IRP PUSHL R3 ; Save IRP address. JSB G^EXE$DEBIT_BYTCNT_ALO ; R2 and R3 are destroyed POPL R3 ; Restore IRP address. BLBC R0,99$ ; Branch on error (SS$_INSFMEM). MOVL R2, IRP$L_SVAPTE(R3) ; Store address of system buffer. ADDL3 #12, R2,- ; Store starting address of system @IRP$L_SVAPTE(R3) ; buffer data area in buffer header. MOVL IRP$L_QIO_P1(R3), 4(R2) ; Store user buffer address in header. MOVL R1, IRP$L_BOFF(R3) ; Store total size of system buffer. 20$: CALL_QIODRVPKT ; Queue the packet and RET (input=R3,R5) 99$: MOVL FDTARG$_PCB(AP), R4 ; Fetch PCB into R4 CALL_ABORTIO ; Abort I/O request and RET (input=R0,R3,R4,R5) .PAGE .SBTTL MK_STARTIO - Driver QIO entry point ;+ ; MK_STARTIO ; ; This routine is the QIO entry point into the driver and is called by ; kernel process sevices as a procedure. Its main function is to dispatch ; to the function-code-specific routine which then executes the QIO. ; ; INPUTS: ; ; R3 - IRP address ; R5 - UCB address ; ; OUTPUTS: ; ; R0 - 1st longword of I/O status: contains status code and ; number of bytes transferred ; R1 - 2nd longword of I/O status: contains a copy of the ; UCB$L_DEVDEPEND field ; All other registers preserved ;- MK_STARTIO: .CALL_ENTRY MOVL 4(AP),R0 ; Get KPB address MOVL KPB$PS_UCB(R0),R5 ; Get UCB address MOVL KPB$PS_IRP(R0),R3 ; Get IRP address .IF DEFINED DEBUG BSBW TRACE_QIO ; Trace the current I/O request .ENDC MOVL UCB$L_PDT(R5),R4 ; Get PDT address MOVL R3,R2 ; Copy IRP address MOVL R5,R3 ; Copy UCB address MK_ALLOC_SCDRP ; Allocate an SCDRP MOVL R2,SCDRP$L_IRP(R5) ; Save IRP address in SCDRP MOVL IRP$PS_KPB(R2),- ; Save KPB address in SCDRP SCDRP$PS_KPB(R5) 1$: MOVL IRP$L_FUNC(R2),- ; Copy function code and modifiers SCDRP$L_FUNC(R5) ; from the IRP to the SCDRP MOVL IRP$L_MEDIA(R2),- ; and media field, SCDRP$L_MEDIA(R5) ; MOVL IRP$L_SVAPTE(R2),- ; SVAPE, SCDRP$L_SVAPTE(R5) ; MOVL IRP$L_BCNT(R2),- ; BCNT, SCDRP$L_BCNT(R5) ; MOVL IRP$L_BOFF(R2),- ; and BOFF SCDRP$L_BOFF(R5) ; ; Fix a synchronization bug in the I/O subsystem which allows virtual functions ; to sneak through FDT processing and be queued to the driver even though ; mapping is disable. BBC #IRP$V_VIRTUAL,- ; Branch if not a virtual I/O function IRP$L_STS(R2),5$ ; MOVL IRP$L_WIND(R2),R0 ; Get window block TSTL WCB$L_NMAP(R0) ; Mapping enabled? BNEQ 5$ ; Branch if so MK_DEACTIVATE_SCDRP CLRSTK=NO ; Deactivate the SCDRP MOVL R3,R5 ; Copy UCB address MOVL UCB$L_VCB(R5),R1 ; Get address of VCB listhead INSQUE (R2),@4(R1) ; Insert entry in blocked I/O list REMQUE @UCB$L_IOQFL(R5),R3 ; Remove I/O packet from device unit queue BVS 3$ ; Branch if no I/O queued CALL_INITIATE ; Go initiate next function RET 3$: BICL #UCB$M_BSY,UCB$L_STS(R5); Clear unit busy CALL_RELCHAN ; Release the channel RET 5$: ; ; ; Allow only physical I/O functions before a PACKACK is issued. ; BBS #IRP$V_PHYSIO,- ; Branch if physical I/O function IRP$L_STS(R2),10$ BBC #UCB$V_VALID,- ; Logical or virtual I/O function UCB$L_STS(R3),- ; Branch if volume is invalid VOLUME_INVALID ; If the last command was a rewind/nowait, the rewind might still be in ; progress. If so, wait for the rewind to complete before executing this ; QIO function. 10$: BBCC #UCB$V_REWIND_INPROG,- ; Branch if last command was not a UCB$L_MK_FLAGS(R3),11$ ; rewind/immediate BSBW WAIT_UNIT_READY ; Otherwise, wait for rewind to complete BLBC R0,COMPLETE_IO ; Branch on error MOVL UCB$L_IRP(R3),R2 ; Restore IRP address BRW 1$ ; Now go execute original command 11$: EXTZV #IRP$V_FCODE,- ; Extract I/O function code #IRP$S_FCODE,- ; IRP$L_FUNC(R2),R1 ; ASSUME IRP$S_FCODE LE 7 ; Allow byte mode dispatch DISPATCH R1,TYPE=B,<- ; Dispatch according to function ,- ; ^X00 ,- ; ^X01 ,- ; ^x06 ,- ; ^X08 ,- ; ^X0B ,- ; ^X0C ,- ; ^X11 ,- ; ^X15 ,- ; ^X1B ,- ; ^X1C ,- ; ^X1D ,- ; ^X20 ,- ; ^X21 ,- ; ^X22 ,- ; ^X23 ,- ; ^X24 ,- ; ^X25 ,- ; ^X26 ,- ; ^X27 ,- ; ^X28 > ; Bogus I/O function code if we fall through. Set illegal function code ; status and complete the I/O. IO_BOGUS: MOVZBL #SS$_ILLIOFUNC,R0 ; Specify the error type BRB COMPLETE_IO IO_NOP: MOVZWL #SS$_NORMAL,R0 ; Set success status BRB COMPLETE_IO ; Complete the I/O VOLUME_INVALID: MOVZWL #SS$_VOLINV,R0 ; It's not a valid volume ; BRB COMPLETE_IO ; Fall through to complete the I/O COMPLETE_IO: MK_DEACTIVATE_SCDRP CLRSTK=NO ; Deactivate the SCDRP MOVL R3,R5 ; Copy UCB address ; If the CANCEL bit is set in the UCB, then the I/O has been canceled and ; REQCOM has already been called for this IRP. The SCSI command, however, is ; allowed to complete (since there's no clean way of aborting a command to ; the tape). In the meantime, the busy bit in the UCB remains set in order to ; prevent any new I/O from being started. Now that the command for the canceled ; I/O has completed, see if any I/O is pending. If so, initiate it. BBCC #UCB$V_CANCEL,- ; Branch if I/O has not been canceled UCB$L_STS(R5),1$ ; REMQUE @UCB$L_IOQFL(R5),R3 ; Any I/O queued to this device? BVS 0$ ; Branch if not CALL_INITIATE ; Go initiate the I/O RET 0$: BICL #UCB$M_BSY,- ; Clear busy bit to allow future I/O UCB$L_STS(R5) ; to be initiated RET ; Return to caller within KP services 1$: .IF DEFINED DEBUG BSBW TRACE_QIO_STAT ; Save the final QIO status in trace buf BLBS R0,5$ ; Branch on success status NOP ; Instruction to trap on QIO with bad status 5$: .ENDC ; The following code segment checks for an error on a virtual I/O function. In ; this case, all virtual I/O packets in the pending queue are removed and placed ; on the blocked I/O list of the volume control block. This allows the magtape ; ACP to perform any operations necessary to recover from the error. It then ; requeues all the I/O from the VCB to the UCB. One specific case in which this ; action is necessary is in encountering a tape mark at the end of a volume. ; The ACP is responsible for the activity necessary to switch to a new volume. PUSHL R0 ; Save final status and count CALL_DIAGBUFILL ; Fill diagnostic buffer if present BLBS (SP),20$ ; Branch if successful completion MOVL UCB$L_IRP(R5),R4 ; Get current IRP BBC #IRP$V_VIRTUAL,- ; Branch if not a virtual I/O function IRP$L_STS(R4),20$ ; ; Temporarily prevent mount verification if a virtual I/O function fails ; with a status that would normally kick in mount verification. CMPW (SP),#SS$_VOLINV ; Volume invalid status? BEQL 7$ ; Branch if so CMPW (SP),#SS$_MEDOFL ; Medium offline status? BNEQ 8$ ; Branch if not 7$: MOVL #SS$_DEVOFFLINE,(SP) ; Return device offline status instead BRB 20$ ; Don't queue I/Os to the blocked queue 8$: MOVL IRP$L_WIND(R4),R4 ; Get window block CLRL WCB$L_NMAP(R4) ; Clear number of mapping pointers MOVL UCB$L_VCB(R5),R4 ; Get address of VCB listhead MOVAB UCB$L_IOQFL(R5),R2 ; Get address of I/O queue listhead MOVL R2,R3 ; Save listhead address 10$: MOVL (R3),R3 ; Get next entry in list CMPL R3,R2 ; End of list? BEQL 20$ ; Branch if so BBC #IRP$V_VIRTUAL,- ; Branch if not a virtual function IRP$L_STS(R3),10$ ; MOVL 4(R3),R3 ; Retrieve address of previous entry REMQUE @(R3),R1 ; Remove entry from Driver queue INSQUE (R1),@4(R4) ; Insert entry in blocked I/O list BRB 10$ ; Repeat for all IPRs in list 20$: POPL R0 ; Retrieve final I/O status MOVL UCB$L_DEVDEPEND(R5),R1 ; Set magtape status and characteristics KP_REQCOM ; Complete I/O request .PAGE .SBTTL MK_CANCEL - Cancel I/O routine ;+ ; MK_CANCEL ; ; This routine cancels an I/O in progress. Since there is no clean way to abort ; a command in progress to the tape, pass the active IRP to REQCOM, but keep ; the BSY bit set in the UCB to prevent any new I/O from being initiated. This ; is accomplished by temporarily emptying the pending I/O queue and calling ; REQCOM with the active IRP. REQCOM sees the pending queue empty and clears ; the BSY bit. When control returns here, the pending queue is restored and ; the BSY bit is set. The CANCEL bit in the UCB is set to indicate that the I/O ; has been canceled. All this activity is synchronized using the fork lock. ; ; Eventually, the SCSI command for the canceled I/O will complete. Just before ; that thread calls REQCOM, it checks the BSY bit. If it finds it set, it ; avoids calling REQCOM. Instead, it attempts to initiate any I/O in the ; pending queue, or clears the BSY bit if no I/O is pending. ; ; Disallow cancel operations for SENSEMODE/SENSECHAR/SETMODE; ; otherwise the canceled IRP will sometimes be given to ; another device before the canceled I/O completes, resulting ; in simultaneous use of that IRP by two devices. (Only these ; 3 functions reference the IRP after the cancel occurs.) ; ; STEP 2 INTERFACE ; ; void CANCEL (channel , IRP *, PCB *, UCB *, reason) ; ; OBSOLETE STEP 1 INPUTS: ; ; R2 - Channel index number ; R3 - IRP address ; R4 - PCB address of procedd canceling I/O ; R5 - UCB address ; R8 - Cancel reason code, one of: ; CAN$C_CANCEL if called through $CANCEL or ; $DALLOC system service ; CAN$C_DASSGN if called through $DASSGN system ; service ; OBSOLETE STEP 1 OUTPUTS: ; ; R0-R3 - Destroyed ; All other registers preserved ;- MK_CANCEL: ; Generate a .CALL_ENTRY and fetch args from stack $DRIVER_CANCEL_ENTRY PRESERVE = BBS #UCB$V_CANCEL,- ; Don't cancel the same IRP twice UCB$L_STS(R5),20$ ; TSTL R3 ; IRP address of 0? (this can happen ; during UNIT INIT in bringing the ; device online) BEQL 20$ ; Branch if not CALL_CANCELIO SAVE_R0R1 = NO ; Set cancel bit if appropriate, trash R0 and R1 BBC #UCB$V_CANCEL,- ; If the cancel bit is not set, UCB$L_STS(R5),20$ ; just return. EXTZV #IRP$V_FCODE,- ; Extract I/O function code #IRP$S_FCODE,- ; IRP$L_FUNC(R3),R0 ; CMPB #IO$_READPBLK,R0 ; Read in progress? BEQL 10$ ; Branch if so, can't cancel CMPB #IO$_WRITEPBLK,R0 ; Write in progress? BEQL 10$ ; Branch if so, can't cancel CMPB #IO$_SENSEMODE,R0 ; Sensemode in progress? BEQL 10$ ; Branch if so, can't cancel CMPB #IO$_SENSECHAR,R0 ; Sensechar in progress? BEQL 10$ ; Branch if so, can't cancel CMPB #IO$_SETMODE,R0 ; Setmode in progress? BEQL 10$ ; Branch if so, can't cancel MOVAL UCB$L_IOQFL(R5),R0 ; Get I/O pending queue listhead address MOVAL UCB$L_FLUSH_IOQFL(R5),R1; And flush I/O queue address MOVL (R0),(R1) ; Temporarily save I/O queue contents MOVL 4(R0),4(R1) ; Including back link MOVL R0,(R0) ; Initialize pending queue MOVL R0,4(R0) ; PUSHR #^M ; Save regs MOVL #SS$_ABORT,R0 ; Set abort status MOVL UCB$L_DEVDEPEND(R5),R1 ; Set magtape status and characteristics .IF DEFINED DEBUG BSBW TRACE_QIO_STAT ; Save the final QIO status in trace buf .ENDC CALL_REQCOM ; Complete the current I/O but do not ; start a new one CLRL UCB$L_IRP(R5) ; I/O packet no longer active CLRL UCB$L_8MM_CHK(R5) ; Clear 8mm COPY check flag BISL #UCB$M_BSY,- ; Set the busy bit to prevent any new UCB$L_STS(R5) ; I/O from being initiated POPR #^M ; Restore regs MOVL (R1),(R0) ; Restore pending I/O queue, fwd link MOVL 4(R1),4(R0) ; Restore back link MOVL R1,(R1) ; Reinitialize flush I/O queue MOVL R1,4(R1) ; RET ; Return to caller 10$: BICL #UCB$M_CANCEL,- ; Indicate cancel is not in progress UCB$L_STS(R5) ; 20$: RET ; Return to caller .PAGE .SBTTL MK_REG_DUMP - Device register dump routine ;+ ; MK_REG_DUMP ; ; This routine dumps device-specific infromation into an errorlog packet. ; The format of this information is as follows: ; ; +-----------------------+ ; | Longword count | 4 bytes ; +-----------------------+ ; | Revision | 1 byte ; +-----------------------+ ; | HW revision | 4 bytes ; +-----------------------+ ; | Error Type | 1 byte ; +-----------------------+ ; | SCSI ID | 1 byte ; +-----------------------+ ; | SCSI LUN | 1 byte ; +-----------------------+ ; | SCSI SUBLUN | 1 byte ; +-----------------------+ ; | Port status | 4 bytes ; +-----------------------+ ; | SCSI CMD | n bytes ; +-----------------------+ ; | SCSI STS | 1 byte ; +-----------------------+ ; | | ; | Additional Data | n bytes ; | | ; +-----------------------+ ; ; The contents of the addition data field depends upon the error type. For ; example, extended sense errors save the extended sense data returned by the ; target in this field. ; ; Step 2 Interface ; ; void REGDUMP (buffer *, CRAM *, UCB *) ; ; Obsolete Step 1 Inputs: ; ; R0 - Output buffer address ; R5 - UCB address ; ; Obsolete Step 1 Outputs: ; ; R0-R3 - Destroyed ; All other registers perserved ;- MK_REG_DUMP: ; Generate a .CALL_ENTRY and fetch args from stack $DRIVER_REGDUMP_ENTRY PRESERVE= PUSHAL (R0)+ ; Save start of data area MOVB #MK_ERROR_REVISION,(R0)+; Save revision level MOVL UCB$L_HW_REV(R5),(R0)+ ; Save hardware revision level MOVB UCB$L_ERROR_TYPE(R5),- ; Save error type (R0)+ MOVZWL UCB$W_UNIT(R5),R1 ; Get unit number CLRL R2 ; Prepare for extended divide EDIV #100,R1,R1,R2 ; Extract SCSI bus ID from unit number MOVB R1,(R0)+ ; Save SCSI bus ID MOVL R2,R1 ; Copy LUN, SUBLUN CLRL R2 ; Prepare for extended divide EDIV #10,R1,R1,R2 ; Extract LUN and SUBLUN MOVB R1,(R0)+ ; Save LUN field MOVB R2,(R0)+ ; Save SUBLUN field MOVL UCB$L_VMS_STATUS(R5),- ; Save port status code (R0)+ MOVW #^XFF00,(R0)+ ; Assume no SCSI CMD,STS available CLRB (R0)+ ; Assume no additional data MOVL UCB$L_SCDRP(R5),R1 ; Get active SCDRP address BEQL 50$ ; Branch if none active MOVL SCDRP$L_CMD_PTR(R1),R2 ; Get address of SCSI command BEQL 50$ ; Branch if none active SUBL #3,R0 ; Back up pointer MOVL (R2)+,R3 ; Get number of SCSI command bytes MOVB R3,(R0)+ ; Save command length 10$: MOVB (R2)+,(R0)+ ; Save a command byte SOBGTR R3,10$ ; Continue for entire SCSI command 20$: MOVB #-1,(R0)+ ; Assume no valid status byte MOVL SCDRP$L_STS_PTR(R1),R2 ; Get address of status byte BEQL 25$ ; Branch if no status byte MOVB (R2),-1(R0) ; Save SCSI status byte 25$: CLRB (R0)+ ; Assume no additonal data MOVL UCB$L_ERROR_TYPE(R5),R2 ; Save error type DISPATCH R2,TYPE=B,<- ; Dispatch according to error code ,- ,- ,- ,- ,- ,- > BUG_CHECK INCONSTATE,FATAL ; Unknown error type. This should ; never happen. ; Error types which have additional data come here. 30$: MOVL SCDRP$L_SVA_USER(R1),R2 ; Get address of additional data BEQL 50$ MOVZBL SCDRP$L_TRANS_CNT(R1),R1; Get length of additional data BEQL 50$ ; Branch if none available ; When we invoke a LOG_ERROR macro, ERL_STD$DEVICERR or ERL_STD$DEVICEATTN ; is invoked to do the following: ; ; 1) Allocate an error log buffer entry; to do this it adds EMB$K_LENGTH ; bytes to the size in DDT$W_ERRORBUF and allocates that much space ; in the current error log buffer; the EMB$K_LENGTH bytes are for a ; header used to manage buffer entries. ; ; 2) Store the address of the error log buffer entry in UCB$L_EMB. The ; base address of the buffer is considered to be the address of the ; first byte after the EMB$K_LENGTH byte header - which is why the ; symbols defined in $EMBHDDEF used to reference the header fields ; are negative. ; ; 3) Load standard, device-independent information into the beginning ; of the buffer; this section is fixed at EMB$L_DV_REGSAV bytes. ; ; 4) Call a device-specific register dump routine passing a buffer ; address of UCB$L_EMB+EMB$L_DV_REGSAV; this is where the register ; dump routine can start writing device and error specific data. ; ; This register dump routine writes two sections of data into the buffer. ; ; The first is device specific but error independent; it will be written ; for every type of error logged by this routine, and it's format is ; described in this routine's header. It's size is not quite fixed, as ; the size of the SCSI command can make it vary, but there's really no ; risk of running off the end of the buffer writing it. ; ; The second is error specific, and it's size will vary with the type of ; error being logged; depending on the amount of error specific data ; we're told is available, it is possible for this section to run off the ; end of the buffer, which could corrupt the header of the next error log ; buffer. For that reason, some special steps are take here to make sure ; that it doesn't happen. ; ; * UCB$L_EMB contains the address of a DDT$W_ERRORBUF byte buffer ; ; * On entry to this routine, a total of DDT$W_ERRORBUF-EMB$L_DV_REGSAV ; bytes are available to be written ; ; * R0 always contains the address of the next byte to be written ; ; The following code calculates the amount of space left in the buffer and ; makes sure that no matter how many bytes of error specific data we have ; available, we don't write past the end of the buffer. MOVL UCB$L_DDT(R5),R3 ; Get the DDT address MOVZWL DDT$W_ERRORBUF(R3),R3 ; Get the buffer size ADDL2 UCB$L_EMB(R5),R3 ; Address after buffer SUBL2 R0,R3 ; Convert to bytes-left CMPL R1,R3 ; Enough room available? BLEQ 35$ ; Branch if so MOVL R3,R1 ; Use all of what's left 35$: MOVB R1,-1(R0) ; Save additional data length 40$: MOVB (R2)+,(R0)+ ; Save a byte of extended sense data SOBGTR R1,40$ ; Repeat for all extended sense data 50$: SUBL (SP),R0 ; Calculate number of bytes saved DECL R0 ; Round up to next longword (+3), but ; don't count LW count field itelf in ; LW count (-4) ASHL #-2,R0,@(SP)+ ; Save in LW count field at top of buffer RET ; Return .PAGE .SBTTL MK_DIAGNOSE - FDT preprocessing for Special pass-through function ;+ ; MK_DIAGNOSE ; ; This routine performs FDT preprocessing including: ; ; - Validating access to the descriptor buffer ; - Validating access to, and locking, the read/write buffer ; - Copying the SCSI command to a buffer in non-paged pool ; ; STEP 2 INTERFACE: ; ; int FDT_ROUTINE (IRP *, PCB *, UCB *, CCB *) ; ; STEP 1 JSB INPUTS: ; ; R3 - IRP address ; R4 - PCB address ; R5 - UCB address ; R6 - CCB address ; AP - Address of first function-dependent argument (P1) ; ; STEP 1 JSB OUTPUTS: ; ; R0-R2 - Destroyed ;- MK_DIAGNOSE: $DRIVER_FDT_ENTRY PRESERVE= MOVL UCB$L_ORB(R5),R9 ;U A; Get address of object rights block CLRQ -(SP) ;U A; terminator and retlen for privilege a MOVL ORB$L_NAME_POINTER(R9),-(SP) ;U A; Bufadr for device name MOVZWL ORB$W_NAME_LENGTH(R9),R9 ;U A; save size of device name ADDL3 #,R9,-(SP) ;U A; itmcod and bufsiz of item ent AUDIT_S_ITMLST = 16 ;U A; Size of the itemlist is 16 bytes MOVL SP,R9 ;U A; save pointer to itemlist $IFPRIV DIAGNOSE, - ;U A; Branch if process has DIAGNOSE priv 10$, - ;U A; success branch MSG=DIAGNOSE_7,- ;U A; Audit message ITMLST=R9, - ;U A; Item List PRESERVE=NO ;U A; MOVL #SS$_NOPRIV,R0 ;U A; Set no privilege status ADDL #AUDIT_S_ITMLST,SP ;U A; Restore stack BRW 50$ ;U A; Branch to abort the I/O 10$: PUSHAL UCB$PS_DIAGNOSE(R5) ;U A; UCB autosense info PUSHL R6 ;U A; CCB address PUSHL R5 ;U A; UCB address PUSHL R4 ;U A; PCB address PUSHL R3 ;U A; UCB address CALLS #5,DKMK$DIAGNOSE_FDT ;U A; Call common FDT routine RET 50$: CALL_ABORTIO ;U A; Abort the I/O with stat .PAGE .SBTTL + .SBTTL + QIO INTERFACE ROUTINES .SBTTL + .SBTTL IO_PACKACK - Pack acknowledge function .SBTTL IO_SENSECHAR - Get device characteristics .SBTTL IO_SENSEMODE - Get device characteristics ;+ ; IO_PACKACK ; IO_SENSEMODE ; IO_SENSECHAR ; ; This routine executes a PACKACK request by polling the device with TEST UNIT ; READY commands until the device is ready, then sending INQUIRY, RECEIVE ; DIAGNOSTIC DATA, MODE SENSE, and MODE SELECT commands. The effect of these ; commands is to prepare the drive to accept READ, WRITE, and tape motion ; commands. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- IO_PACKACK: BSBW PACKACK_SEQ BRW COMPLETE_IO ; Complete this I/O function PACKACK_SEQ: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= BSBW WAIT_UNIT_READY ; Wait for the device to spin up BLBC R0,30$ ; Branch on error BSBW INQUIRY ; Execute an INQUIRY command BLBC R0,30$ ; Branch on error BSBW RECEIVE_DIAG ; Execute a received diagnostic data cmd BLBC R0,30$ ; Branch on error BSBW MODE_SENSE ; Execute a MODE SENSE command BLBC R0,30$ ; Branch on error BSBW MODE_SELECT ; Set error recovery parameters, block ; size, etc. (if necessary) BLBC R0,30$ ; Branch on error BSBW CHECK_SKIPFILE_SUPPORT ; Check if READ POSITION cmd supported BSBW CHECK_COMPACTION_SUPPORT ; check if device supports data compaction 20$: BSBW SET_CONN_CHAR ; Set up the connection characteristics BLBC R0,30$ ; Branch on error BISL #UCB$M_VALID,- ; Set volume valid UCB$L_STS(R3) ; 30$: RSB ; Return to caller IO_SENSEMODE: IO_SENSECHAR: BSBW PACKACK_SEQ BLBC R0,20$ ; Branch on error ; ; Return device characteristics if user supplied buffer ; ; ; the IFNOT_TSZO7 is commented out below to allow the DEVDEPEND info ; to be returned for all devices ; ; IFNOT_TSZ07 10$ ; Branch if not TSZ07 MOVL SCDRP$L_IRP(R5),R1 ; Get pointer to IRP TSTL IRP$L_SVAPTE(R1) ; Is there a user supplied buffer? BEQL 10$ ; Branch if not. ASSUME UCB$L_DEVDEPEND EQ UCB$B_DEVCLASS+4 ASSUME UCB$L_DEVDEPND2 EQ UCB$L_DEVDEPEND+4 MOVL @IRP$L_SVAPTE(R1),R0 ; Get system buffer data area address. MOVL UCB$B_DEVCLASS(R3),(R0)+ ; Store dev class, type, buffer size. MOVL UCB$L_DEVDEPEND(R3),- ; Store device characteristics. (R0)+ CMPL IRP$L_BCNT(R1), #12 ; User buffer length = 12? BNEQ 10$ ; Branch if not. MOVL UCB$L_DEVDEPND2(R3),- ; Store extended device characteristics. (R0)+ ; 10$: MOVZWL #SS$_NORMAL,R0 ; Success status 20$: BRW COMPLETE_IO ; Complete this I/O function .PAGE .SBTTL IO_DSE - Data security erase ;+ ; IO_DSE ; ; This routine sends an ERASE command to the tape to erase all the data from ; the current position to the end of the tape. The tape is then rewound. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- IO_DSE: IO_ERASETAPE: BICL #,- ; UCB$L_DEVDEPEND(R3) ; MOVAL CMD_ERASE,R2 ; Get address of erase command SETUP_CMD ; Setup the command SEND_COMMAND_ORDERED ; Send the command CLEANUP_CMD ; Cleanup from the SCSI command BLBC R0,COMPLETE_IO ; Branch on error BRW IO_REWIND ; Otherwise, go rewind the tape .PAGE .SBTTL IO_SETMODE - Set mode ;+ ; IO_SETMODE ; ; This routine sends a MODE_SELECT command to the tape to set up various drive ; characteristics including default block size, buffered (streaming) mode, ; number of fillers, and infinite reselection timeout. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ; ;- IO_SETMODE: MOVW SCDRP$L_MEDIA+2(R5),- ; Set new default buffer size UCB$W_DEVBUFSIZ(R3) ; IF_TSZ07 10$ ; Branch if TSZ07 ; Add code for sw front panel density control ; Density will be in devdepnd3 lo byte as binary number. If zero, do usual ;Note we leave tsz07 alone more or less. tstb ucb$l_devdepnd3(r3) ; Is the user density null? beql 7$ ; if so skip special stuff ; Set density value. movw ucb$l_devdepnd3(r3),UCB$W_MK_DENSITY(R3) ; Copy density 7$: BSBW MODE_SELECT ; Send a mode select command BLBS R0,10$ ; attempt to set compaction/density BRW 30$ ; branch on error ; ; - TSZ07 set new density if at BOT ; - other devices check for compaction enable/disable ; 10$: TSTL UCB$L_RECORD(R3) ; Are we at BOT? BNEQ 25$ ; Branch if not, don't change density MOVL SCDRP$L_IRP(R5),R1 ; Get pointer to IRP MOVZWL IRP$L_MEDIA+4(R1),- ; Save characteristics in unused UCB$L_BOFF(R3) ; UCB location. EXTZV #MT$V_DENSITY,- ; Get density selection #MT$S_DENSITY,- UCB$L_BOFF(R3),R0 ; ; Do density/compaction checks ; IFNOT_TSZ07 20$ ; ; TSZ07 density checks ; ASSUME MT$K_DEFAULT EQ 0 TSTW R0 ; default density ? BNEQ 13$ ; NEQ = no CLRW UCB$W_MK_DENSITY(R3) ; Set density to default BRB 17$ ; issue default density mode_select 13$: CMPW #MT$K_PE_1600,R0 ; Set 1600 bpi? BEQL 15$ ; Branch if so CMPW #MT$K_GCR_6250,R0 ; Set 6250 bpi? BEQL 15$ ; Branch if so MOVZWL #SS$_BADPARAM,R0 ; Invalid density selected BRW COMPLETE_IO ; Finished 15$: SUBW3 #2,R0,UCB$W_MK_DENSITY(R3) ; Compute device density (2 less ; less than VMS density values). 17$: BSBW MODE_SELECT ; Send a mode select command BLBC R0,30$ ; Branch on error MOVL SCDRP$L_IRP(R5),R1 ; Get pointer to IRP MOVZWL IRP$L_MEDIA+4(R1),- ; Save characteristics in unused UCB$L_BOFF(R3) ; UCB location. EXTZV #MT$V_DENSITY,- ; Get density selection again #MT$S_DENSITY,- UCB$L_BOFF(R3),R0 INSV R0,- ; Store density value in UCB #MT$V_DENSITY,- ; device characteristics field. #MT$S_DENSITY,- UCB$L_DEVDEPEND(R3) BRB 25$ ; all done ; ; All other devices get checked for compaction enable/disable ; 20$: CMPW #MT$K_SCSI_DC1,R0 ; Set Compaction mode? BNEQ 21$ ; *** IGNORE ANY OTHER DENSITY VALUES MOVL #1, R0 ; flag for SETUP_COMPACTION = ON BRB 22$ 21$: CLRL R0 ; flag compaction off 22$: ; Only attempt to issue mode_select if BITL #MT2$M_COMP_SUP,- ; compaction is supported UCB$L_DEVDEPND2(R3) ; BEQL 25$ ; branch if not tstw ucb$l_devdepnd3(r3) ; front panel overrides compaction bneq 23$ BSBW SETUP_COMPACTION ; do MODE_SELECT for compaction page BLBC R0,30$ ; Branch if error 23$: MOVL SCDRP$L_IRP(R5),R1 ; Get pointer to IRP EXTZV #MT$V_DENSITY,- ; Get density selection again #MT$S_DENSITY,- IRP$L_MEDIA+4(R1),R1 INSV R1,- ; Store density value in UCB #MT$V_DENSITY,- ; device characteristics field. #MT$S_DENSITY,- UCB$L_DEVDEPEND(R3) BRB 30$ ; all done 25$: MOVZWL #SS$_NORMAL,R0 ; Success status 30$: BRW COMPLETE_IO ; Complete this I/O function .PAGE .SBTTL IO_WRITEOF - Write tape mark .SBTTL IO_WRITEMARK - Write tape mark ;+ ; IO_WRITEOF ; IO_WRITEMARK ; ; This routine writes one tapemark at the current position on the tape. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- IO_WRITEMARK: IO_WRITEOF: BICL #,- ; UCB$L_DEVDEPEND(R3) ; MOVAL CMD_WRITE_FILEMARKS,R2 ; Get address of write filemarks command SETUP_CMD ; Setup the command MOVL SCDRP$L_CMD_PTR(R5),R1 ; Get the SCSI command address MOVB #1,SCSI_WFM$B_CNT+4+2(R1); Specify one filemark 10$: SEND_COMMAND_ORDERED ; Send the command BLBS R0,15$ ; Branch if success CMPL R0,#SS$_ENDOFTAPE ; End of tape? If so, treat as success BEQL 15$ ; Branch if so CMPL R0,#SS$_PARITY ; Media error? BNEQ 20$ ; Branch if not 15$: INCL UCB$L_RECORD(R3) ; Update record count 20$: CLEANUP_CMD ; Cleanup from the SCSI command BRW COMPLETE_IO ; Complete this I/O function .PAGE .SBTTL IO_READPBLK - Read a set of blocks from the SCSI drive ;+ ; IO_READPBLK ; ; This routine reads a record from the tape. If the function is a REVERSE READ, ; a backspace of one record is performed both prior to and after the read, as ; many SCSI tape drives, including the TZK50 and TZ30, don't support the READ ; REVERSE command. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- IO_READPBLK: IO_READLBLK: BICL #,- ; UCB$L_DEVDEPEND(R3) ; BBC #IO$V_REVERSE,- ; Branch if this is NOT a read reverse SCDRP$L_FUNC(R5),10$ ; function MNEGW #1,R0 ; Prepare to backup one record PUSHL SCDRP$L_BCNT(R5) ; Save read byte count BSBW SKIP_RECORD ; Backup one record POPL SCDRP$L_BCNT(R5) ; Restore read byte count BLBC R0,50$ ; Branch on error 10$: MOVAL CMD_READ,R2 ; Address of read command SETUP_CMD ; Setup the command ADDL3 #<4+SCSI_RD$B_LEN+3>,- ; Get address just beyond transfer SCDRP$L_CMD_PTR(R5),R0 ; length field in the SCSI command MOVAL SCDRP$L_BCNT(R5),R1 ; Get address of byte count field in SCRRP .REPT 3 MOVB (R1)+,-(R0) ; Fill in the transfer length field .ENDR MOVL #IRP$M_FUNC,- ; Set the FUNC but to indicate this SCDRP$IS_STS(R5) ; is a read function BISB #SCDRP$M_FLAG_BUFFER_MAPPED,-; Remember the fact that a buffer SCDRP$L_SCSI_FLAGS(R5) ; has been mapped SPI$BUFFER_MAP ; Map the user's buffer SEND_COMMAND_ORDERED ; Send the SCSI command CLEANUP_CMD ; Cleanup from the command INCL UCB$L_RECORD(R3) ; Keep track of forward tape position BLBS R0,15$ ; Branch on success CMPL R0,#SS$_DATAOVERUN ; If overrun, treat as success BEQL 15$ ; Branch if so CMPL R0,#SS$_ENDOFTAPE ; If EOT, treat as success BNEQ 50$ ; Branch if not MOVW #SS$_NORMAL,R0 ; Change EOT status to success 15$: MOVL SCDRP$L_TRANS_CNT(R5),R1; Get the transfer count value BBC #IO$V_REVERSE,- ; Branch if this is NOT a read reverse SCDRP$L_FUNC(R5),20$ ; function PUSHL R0 ; Save status from read PUSHL R1 ; Save the transfer count value MNEGW #1,R0 ; Prepare to backup one record BSBW SKIP_RECORD ; Backup one record BLBC R0,60$ ; If skip fails, use that as the status ; code POPL R1 ; Restore transfer count POPL R0 ; Restore status from read 20$: INSV R1,#16,#16,R0 ; Place transfer count in high-order ; word of R0 50$: BRW COMPLETE_IO ; Complete this I/O function 60$: POPL R2 ; Clean off the internal stack POPL R2 ; BRB 50$ ; Use common exit .PAGE .SBTTL IO_WRITEPBLK - Write a set of blocks to the SCSI drive ;+ ; IO_WRITEBLK ; ; This routine writes a record to the tape. If the function is a REVERSE WRITE, ; a backspace of one record is performed both prior to and after the write, as ; many SCSI tape drives, including the TZK50 and TZ30, don't support the WRITE ; REVERSE command. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- IO_WRITEPBLK: IO_WRITELBLK: BICL #,- ; UCB$L_DEVDEPEND(R3) ; BBC #IO$V_REVERSE,- ; Branch if this is NOT a write reverse SCDRP$L_FUNC(R5),10$ ; function MNEGW #1,R0 ; Prepare to backup one record PUSHL SCDRP$L_BCNT(R5) ; Save read byte count BSBW SKIP_RECORD ; Backup one record POPL SCDRP$L_BCNT(R5) ; Restore read byte count BLBC R0,50$ ; Branch on error 10$: MOVAL CMD_WRITE,R2 ; Address of read command SETUP_CMD ; Setup the command ADDL3 #<4+SCSI_WRT$B_LEN+3>,- ; Get address just beyond transfer SCDRP$L_CMD_PTR(R5),R0 ; length field in the SCSI command MOVAL SCDRP$L_BCNT(R5),R1 ; Get address of byte count field in IRP .REPT 3 MOVB (R1)+,-(R0) ; Fill in the transfer length field .ENDR CLRL SCDRP$IS_STS(R5) ; Clear the FUNC but to indicate this ; is a write function BISB #SCDRP$M_FLAG_BUFFER_MAPPED,-; Remember the fact that a buffer SCDRP$L_SCSI_FLAGS(R5) ; has been mapped SPI$BUFFER_MAP ; Map the user's buffer SEND_COMMAND_ORDERED ; Send the SCSI command BLBS R0,15$ ; Branch on success IFNOT_8MM 15$ ; Br if not 8MM TSTL UCB$L_8MM_CHK(R3) ; Should 8MM COPY check be done? BEQL 15$ ; Br if no BSBW DO_8MM_COPY_CHK ; Attempt recovery processing BLBC R0,15$ ; Branch on error ; We have just successfully repositioned the tape in the special case of 8MM ; drives, so we may now retry the write command that originally failed. ; Before re-using the SCDRP, deallocate/reallocate a command buffer and ; unmap/remap the user buffer, as smart adapters require. SPI$BUFFER_UNMAP ; Un-map data buffer (but don't ; deallocate data buffer) MOVL SCDRP$L_CMD_BUF(R5),R0 ; Get address of command buffer SPI$CMD_BUFFER_DEALLOC ; Dealloc command buffer MOVAL CMD_WRITE,R2 ; Address of read command SETUP_CMD ; Setup the command ADDL3 #<4+SCSI_WRT$B_LEN+3>,- ; Get address just beyond transfer SCDRP$L_CMD_PTR(R5),R0 ; length field in the SCSI command MOVAL SCDRP$L_BCNT(R5),R1 ; Get address of byte count field in IRP .REPT 3 MOVB (R1)+,-(R0) ; Fill in the transfer length field .ENDR CLRL SCDRP$IS_STS(R5) ; Clear the FUNC but to indicate this ; is a write function BISB #SCDRP$M_FLAG_BUFFER_MAPPED,-; Remember the fact that a buffer SCDRP$L_SCSI_FLAGS(R5) ; has been mapped SPI$BUFFER_MAP ; Map the user's buffer SEND_COMMAND_ORDERED ; Send the SCSI WRITE command again ; Common cleanup processing 15$: CLEANUP_CMD ; Cleanup from the command BLBS R0,20$ ; Branch on success CMPL R0,#SS$_ENDOFTAPE ; End of tape? If so, treat as success BEQL 20$ ; Branch if so CMPL R0,#SS$_PARITY ; Media error? BNEQ 50$ ; Branch if not 20$: INCL UCB$L_RECORD(R3) ; Keep track of forward tape position MOVL SCDRP$L_TRANS_CNT(R5),R1; Get transfer count BBC #IO$V_REVERSE,- ; Branch if this is NOT a read reverse SCDRP$L_FUNC(R5),30$ ; function PUSHR #^M ; Save command status, transfer count MNEGW #1,R0 ; Prepare to backup one record BSBW SKIP_RECORD ; Backup one record MOVL R0,R2 ; Copy status for backspace command POPR #^M ; Restore write status, transfer count BLBS R2,30$ ; Branch if backspace suceeded MOVL R2,R0 ; Otherwise, return backupspace status 30$: INSV R1,#16,#16,R0 ; Return transfer count in h.o. word of R0 50$: BRW COMPLETE_IO ; Complete this I/O function .PAGE .SBTTL IO_SKIP_RECORD - Move n records ;+ ; IO_SKIP_RECORD ; ; This routine skips n records, where n is a signed word in the SCRP$L_MEDIA ; field. The skip operation stops upon encountering a tape mark. The actual ; number of records skipped is returned in the h.o. word of R0. If two ; consecutive tape marks are encountered while skipping forward, and the NOT ; mounted files-11, then SS$_ENDOFVOLUME status is returned. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status, actual skip count in h.o. word ; R1,R2 - Destroyed ; All other registers preserved ; ;- .ENABL LSB IO_SKIP_RECORD: CVTWL SCDRP$L_MEDIA(R5),R0 ; Number of records to skip BLSS IO_SKIP_RECORD_REV ; Branch if negative BEQL 50$ ; Branch if zero (nothing to do) BSBW SKIP_RECORD ; Skip the specified number of records BLBS R0,10$ ; Branch on success CMPL R0,#SS$_ENDOFTAPE ; End of tape? BEQL 10$ ; Branch if so CMPL R0,#SS$_ENDOFFILE ; Tapemark encountered? BNEQ 20$ ; Branch if not BSBW CHECK_EOV ; Check for logical end-of-volume CMPL R0,#SS$_ENDOFVOLUME ; End of volume? BNEQ 10$ ; Branch if so DECW R1 ; Tape was backed up one record 10$: INSV R1,#16,#16,R0 ; Return skip count in high-order 20$: BRW COMPLETE_IO ; Complete the I/O request IO_SKIP_RECORD_REV: CLRL UCB$L_BOFF(R3) ; Initialize accumulated skip count 30$: BSBW SKIP_RECORD ; Skip the specified number of records SUBL R1,UCB$L_BOFF(R3) ; Update accumulated skip count BLBS R0,40$ ; Branch on success CMPL R0,#SS$_ENDOFFILE ; Tapemark encountered? BEQL 40$ ; Branch if so CMPL R0,#SS$_ENDOFTAPE ; End of tape? BNEQ 20$ ; Branch if not TSTL UCB$L_RECORD(R3) ; Are we at BOT? BEQL 35$ ; Branch if so TSTW R1 ; Any records skipped? BGEQ 35$ ; Branch if not making any progress ADDL3 SCDRP$L_MEDIA(R5),- ; Prepare to skip the remaining number UCB$L_BOFF(R3),R0 ; of records BLSS 30$ ; Branch if more records to skip 35$: MOVL #SS$_NORMAL,R0 ; Treat EOT or BOT as success 40$: MOVL UCB$L_BOFF(R3),R1 ; Place total skip count in R1 BRB 10$ ; Use common exit path 50$: CLRL R1 ; No records skipped MOVZWL #SS$_NORMAL,R0 ; Set success status BRB 10$ ; Use common exit path .DSABL LSB .PAGE .SBTTL IO_SKIP_FILE - Move n tapemarks (in either direction) ;+ ; IO_SKIP_FILE ; ; This routine spaces n tapemarks in either direction. SCDRP$L_MEDIA contains ; a signed integer specifying the number of tapemarks to space. If possible, ; use the SCSI SPACE FILEMARKS command followed by the READ POSITION command ; (READ POSITION allows us to keep track of first block location). Otherwise ; use the space record option, and each time a filemark is encountered, we ; accumulate the number of records skipped. ; Pre-requisites for employing the faster performing space-by-filemark are: ; ; o Device must support the READ_POSITION command ; o Device must generate Blank Check when encountering logical EOV ; (TSZ05/7 do not meet this prerequisite) ; o The space count must be other than +1 or +2, since in those cases ; the overhead of Space by Filemarks actually degrades performance. ; ; A note on the skip-by-record algorithm: ; When skipping forward, a record skip count less than the maximum is used ; in order to allow for reasonable responsive I/O cancels. Because of the way ; tape drives implement reverse skip record (rewind, space forward), this same ; method can not be used for space reverse operations (i.e., the maximum ; reverse record count is used). ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ;- .ENABL LSB IO_SKIP_FILE: CVTWL SCDRP$L_MEDIA(R5),R1 ; Get number of files to skip MOVL R1,UCB$L_BOFF(R3) ; Save it in a convenient place MOVL R1,UCB$L_BCNT(R3) ; Save another copy CMPL #1,R1 ; Optimize for the most common case ; of skip count = 1 BEQL 10$ ; Skip-by-record is faster in this case CMPL #2,R1 ; Optimize for the next common case ; of skip count = 2 BEQL 10$ ; Skip-by-record is faster in this case BBS #UCB$V_SKIPFILE_SUPPORTED,- UCB$L_MK_FLAGS(R3),- ; If possible, for count > 2, SPACE_FILEMARKS ; use SPACE FILEMARKS/READ POSITION TSTL R1 ; Test space count BLSS IO_SKIP_FILE_REV ; Branch if negative count BEQL 20$ ; Branch if zero skip count ; If here, then use the skip-by-record method 10$: BBS #UCB$V_CANCEL,- ; Branch if I/O has been canceled? UCB$L_STS(R3),20$ ; MOVW #^X7FFF,R0 ; Forward skip count BSBW SKIP_RECORD ; Skip records (updating UCB$L_RECORD) BLBS R0,10$ ; Branch if no tapemark found CMPL R0,#SS$_ENDOFFILE ; Tape mark encountered? BNEQ 40$ ; Branch if not BSBW CHECK_EOV ; Check for logical end-of-volume CMPL R0,#SS$_ENDOFVOLUME ; Logical EOV? BEQL 30$ ; Branch if so CMPL R0,#SS$_ENDOFFILE ; EOF status? BNEQ 40$ ; Branch if not DECL UCB$L_BOFF(R3) ; One more tapemark found BGTR 10$ ; Branch if not done yet 20$: MOVW #SS$_NORMAL,R0 ; Set success status 30$: SUBL3 UCB$L_BOFF(R3),- ; Calculate actual number of UCB$L_BCNT(R3),R1 ; files skipped INSV R1,#16,#16,R0 ; Save in high-order word of R0 40$: BRW COMPLETE_IO IO_SKIP_FILE_REV: 50$: BBS #UCB$V_CANCEL,- ; Branch if I/O has been canceled? UCB$L_STS(R3),20$ ; MOVW #^X8000,R0 ; Maximum reverse skip count BSBW SKIP_RECORD ; Skip records (updating UCB$L_RECORD) BLBS R0,50$ ; Branch if no tapemark found CMPL R0,#SS$_ENDOFTAPE ; End of tape? BEQL 20$ ; Branch if not CMPL R0,#SS$_ENDOFFILE ; Tape mark encountered? BNEQ 40$ ; Branch if not 60$: INCL UCB$L_BCNT(R3) ; One more tapemark found BLSS 50$ ; Branch if more to do BRB 20$ ; Use common exit ; If here, then use the skip-by-file method SPACE_FILEMARKS: ; Do Space Filemarks to move the tape BBS #UCB$V_CANCEL,- ; Branch if I/O has been canceled? UCB$L_STS(R3),20$ ; MOVL R1,R0 ; Forward skip count BLSS SPACE_FILEMARKS_REV ; Branch if negative count BEQL 20$ ; Exit if zero count BSBW SKIP_FILE ; Skip tapemarks, return count in R1 BLBS R0,70$ ; Case 1: SS$_NORMAL was returned CMPL R0,#SS$_ENDOFVOLUME ; Case 2: Logical EOV status? BNEQ 140$ ; Case 3: Fall through, serious error BRW 75$ ; Go to Logical EOV processing ; Case 1: SS$_NORMAL was returned. ; ; If here, then SS$_NORMAL has just been returned. There are two sub-cases: ; the tape is now positioned on some tapemark in the middle of the tape, ; or the tape is positioned on the second tapemark within an EOV tapemark pair. ; In the latter case it is important to return SS$_ENDOFVOLUME instead of ; success. In order to determine which case we have, employ the following ; logic: upon SS$_NORMAL, back up to the position just before the current ; tapemark, and examine whether it is a tapemark as well. If not, then we ; know we are not at EOV after all; so skip forward to get to our original ; position. If we are in an EOV situation, however, we must change the status ; code from SS$_NORMAL to SS$_ENDOFVOLUME. ; ; (In more detail), to check whether the preceding record position is a tape ; mark as well, refer to the diagram below and note that: ; At this point the tape is positioned on the end-of-partition side ("A") ; of the tape mark. We must space back one file to get to the beginning-of- ; partition side ("B") of the tape mark, then space back one record (to "C") ; and test for a tapemark-encounterd Check Condition. ; ; ----+----------+----------+-------------------------------------- ; |Record to | Tapemark | ; |be tested | | ; ----+----------+----------+-------------------------------------- ; (C) (B) (A) ; Space reverse by one filemark 70$: MOVL #-1,R0 ; Prepare to back up to beg-of-partn PUSHL R1 ; Save actual skip count BSBW SKIP_FILE ; Get to beginning-of-partition side POPL R1 ; Restore actual skip count BLBC R0,140$ ; Exit if error ; Space reverse by one record MOVL #-1,R0 ; Prepare to back up one record PUSHL R1 ; Save actual skip count BISL #UCB$M_NO_POSITION_UPDATE,- ; Do not update UCB$L_RECORD UCB$L_MK_FLAGS(R3) ; at this time BSBW SKIP_RECORD ; Jump back over preceding record BICL #UCB$M_NO_POSITION_UPDATE,- ; Clear indicator flag UCB$L_MK_FLAGS(R3) POPL R1 ; Restore actual skip count .BRANCH_LIKELY BLBS R0,72$ ; Preceding record is not a tapemk CMPL R0,#SS$_ENDOFFILE ; EOF status? BNEQ 140$ ; Branch if not, serious problem ; Case 1a: ; We have hit the case of 2 consecutive tapemarks, so space forward one ; tapemark to position the tape between the 2 marks. MOVL #1,R0 ; Prepare to position between 2 tm's PUSHL R1 ; Save actual skip count BSBW SKIP_FILE ; Position the tape POPL R1 ; Restore actual skip count BLBC R0,140$ ; Exit if error MOVL #SS$_ENDOFVOLUME,R0 ; We hit a tapemark, so return end-of- ; volume status DECL R1 ; We just backed up one filemark BRW 80$ ; Join common exit code ; Case 1b: ; The record we just backed up to is not a tapemark. So we are not at end ; of logical volume. So restore position by spacing forward (across both ; the record and the subsequent tapemark). Space by file instead of by record ; to avoid a Check Condition. 72$: MOVL #1,R0 ; Prepare to skip forward acros tpmark PUSHL R1 ; Save actual skip count BSBW SKIP_FILE ; Skip forward one tapemark POPL R1 ; Restore actual skip count BLBS R0,80$ ; Tape is now back to original position BRW 140$ ; Branch if err, serious problem exists ; Case 2: Logical EOV status ; ; If here, then SS$_ENDOFVOLUME has just been returned. Back up one tapemark. ; While it may seem similar to the code above, it is kept separate in ; order to detect the error condition that SS$_ENDOVOLUME (signified by a ; BLANK CHECK) was returned by SKIP_FILE, but the tape does not end in ; a pair of tapemarks. 75$: MOVL #-1,R0 ; Prepare to back up one record PUSHL R1 ; Save actual skip count BISL #UCB$M_NO_POSITION_UPDATE,- UCB$L_MK_FLAGS(R3) BSBW SKIP_RECORD ; Position tape between filemarks BICL #UCB$M_NO_POSITION_UPDATE,- UCB$L_MK_FLAGS(R3) POPL R1 ; Restore actual skip count CMPL R0,#SS$_ENDOFFILE ; EOF status? BNEQ 140$ ; Branch if not, serious problem exists MOVL #SS$_ENDOFVOLUME,R0 ; Return end of volume status DECL R1 ; We just backed up one filemark ; Common code for Space Forward processing 80$: BSBW READ_POSITION ; Update ucb$l_record BISL #MT$M_EOF,- ; We are positioned on a tapemark UCB$L_DEVDEPEND(R3) MOVL UCB$L_RECORD(R3),- ; Update last tapemark found during UCB$L_PREV_TM(R3) ; a forward search INSV R1,#16,#16,R0 ; Save in high-order word of R0 BRW 140$ ; Go to COMPLETE_IO SPACE_FILEMARKS_REV: BSBW SKIP_FILE ; Skip files, return actual count in R1 BLBS R0,100$ ; Branch if success CMPL R0,#SS$_ENDOFTAPE ; Beginning of tape? BNEQ 140$ ; Other errors serious - exit MOVL #SS$_NORMAL,R0 ; But BOT is not an error 100$: BISL #UCB$M_REV_SKIP,- ; Indicate direction (needed by UCB$L_MK_FLAGS(R3) ; READ POSITION) BSBW READ_POSITION ; Update ucb$l_record BICL #UCB$M_REV_SKIP,- ; Clear flag UCB$L_MK_FLAGS(R3) MNEGL R1,R1 ; IOSB needs unsigned count INSV R1,#16,#16,R0 ; Save in high-order word of R0 ; Space Filemarks exit path (all cases, Forward and Reverse) 140$: BRW 40$ ; Go to common exit and COMPLETE_IO .DSABL LSB .PAGE .SBTTL READ_POSITION - read tape record position ; READ_POSITION ; ; Do Read Position command to fill in UCB$L_RECORD ; ; INPUTS: ; ; R0 - VMS status from last Space command ; R3 - UCB address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R2 - Destroyed ; All other registers preserved. ; READ_POSITION: .JSB_ENTRY INPUT=,SCRATCH=,PRESERVE= MOVL R0,R6 ; Save status MOVAL CMD_READ_POSITION,R2 ; Address of READ POSITION command SETUP_CMD ; Perform setup for SCSI command SEND_COMMAND_ORDERED ; Send the SCSI command BLBC R0,30$ ; Branch on error CMPL SCDRP$L_TRANS_CNT(R5),- ; Sufficient data returned? #20 ; READ POS data length should equal 20. BLSS 30$ ; No, declare the command unsupported MOVL SCDRP$L_SVA_USER(R5),R0 ; Get address of READ POSITION data BBS #BPU_BIT,- ; If block position unknown, (R0),30$ ; declare the command unsupported ; Note: BPU bit is in first data byte MOVL UCB$L_RECORD(R3),R2 ; Save current position MOVAB 8(R0),R0 ; Prepare to update UCB$L_RECORD ; Note: Block position occupies bytes ; 4,5,6,7 (MSB->LSB) in READ POS data MOVAB UCB$L_RECORD(R3),R1 .REPT 4 MOVB -(R0),(R1)+ ; Update UCB$L_RECORD .ENDR ; Sanity check: If the skip direction was forward, UCB$L_RECORD should ; increase, otherwise decrease. BBS #UCB$V_REV_SKIP,- ; Is this a reverse skip? UCB$L_MK_FLAGS(R3),10$ ; Forward skip sanity check CMPL UCB$L_RECORD(R3),R2 ; Is new value > old value ? BGTR 20$ ; Yes, good, so exit normally. BLSS 30$ ; It went backward, something is wrong. ; Allow for the possibility that a skip forward was issued while the previous ; position was EOV, so that both old and new values are the same. CMPL R6,#SS$_ENDOFVOLUME ; EOV? BEQL 20$ ; Yes, it's okay to have same position BRW 30$ ; Else error ; Reverse skip sanity check 10$: CMPL UCB$L_RECORD(R3),R2 ; Is new value < old value ? BLSS 20$ ; Yes, so this is success ; Allow for the possibility that a skip reverse was issued while the ; previous position was BOT, so that both old and new values = 0. BBC #MT$V_BOT,- ; If new value >= old value, and tape UCB$L_DEVDEPEND(R3),30$ ; is not at BOT, something is wrong. ; Common exit 20$: CLEANUP_CMD ; Clean up the command RSB ; Error path when READ_POSITION fails 30$: BICL2 #UCB$M_SKIPFILE_SUPPORTED,-; READ POSITION command unsupported UCB$L_MK_FLAGS(R3) LOG_ERROR - TYPE=SEND_CMD_ERROR,- VMS_STATUS=#SS$_NORMAL,- UCB=R3 BSBW SET_TAPE_LOST ; Set tape lost BRW 20$ .PAGE .SBTTL IO_UNLOAD - Rewind and unload the tape ;+ ; IO_UNLOAD ; ; This routine rewinds amd unloads the drive and clears the VALID bit in the ; UCB. ; ; INPUTS: ; ; R2 - IRP address ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- IO_RETENSION: .ENABLE LSB IF_TZK10 2$ ; If TZK10, do retension IF_TZK11 2$ ; If TZK11, do retension BRW 11$ 2$: MOVAL CMD_RETENSION,R2 ; Get address of Retension command BRB 5$ ; Continue with CMD set up IO_UNLOAD: IO_REWINDOFF: BBS #IO$V_RETENSION,- ; Check to see if the RETENSION bit is SCDRP$L_FUNC(R5),- IO_RETENSION ; set - if so, branch to IO_RETENSION ADDL3 #MAX_UNLOAD_TIME,- ; Save time at which unload must G^EXE$GL_ABSTIM,- ; be complete UCB$L_UNLOAD_TIME(R3) ; BISW #UCB$M_UNLOAD_INPROG,- ; Indicate unload may be in pro UCB$L_MK_FLAGS(R3) ; when next QIO is issued MOVAL CMD_UNLOAD,R2 ; Get address of unload command 5$: SETUP_CMD ; Setup the command SEND_COMMAND_ORDERED ; Send the command CLEANUP_CMD ; Cleanup from the SCSI command BLBC R0,7$ ; Branch on error ; Workaround for the TZK50: the unload command can take up to 20 ms ; to "take", i.e., subsequent commands sent to the drive within 20 ms ; of an unload can operate as though the unload never occurred. For example, ; a test unit ready command sent immediately after an unload will return ; success, when it should return unit not ready. This can cause errors ; during multi-volume backup operations. Therefore, stall for at least a ; second to allow the unload to do its thing. IFNOT_TK50 7$ ; Branch if not a TK50 PUSHL # SPL$C_IOLOCK8 ; Set the required fork lock PUSHAQ TWO_SECONDS ; Set time delay PUSHL SCDRP$PS_KPB(R5) ; Set KPB address CALLS #3,G^EXE$KP_TQE_WAIT ; Fork and wait the desired time MOVZWL #SS$_NORMAL,R0 ; Restore success status 7$: BICL #UCB$M_VALID,- ; Clear the volume valid bit in UCB$L_STS(R3) ; the UCB BISL #,- ; Mark beginning of tape UCB$L_DEVDEPEND(R3) ; BICL #,- ; and end of file UCB$L_DEVDEPEND(R3) ; CLRL UCB$L_RECORD(R3) ; Initialize record field MNEGL #2,UCB$L_PREV_TM(R3) ; No previous tape mark ; Unload requested, inform the Media Management System MOVL #MME$_UNLOAD, R0 ; load MME event code. PUSHL R5 ; save the CDRP address on the stack. MOVL R3, R5 ; copy the UCB address into R5. JSB G^MME$$DEV_EVENT ; invoke the MME call-out routine. POPL R5 ; restore the CDRP address. 10$: BRW COMPLETE_IO ; Complete this I/O function 11$: MOVZBL #SS$_ILLIOFUNC,R0 ; Not a TZK10, bad func code BRB 10$ ; for this device .DISABLE LSB .PAGE .SBTTL IO_AVAILABLE - Make drive available (but don't unload it) ;+ ; IO_AVAILABLE ; ; This routine rewinds the tape and clears the VALID bit in the UCB. Since ; this function commonly follows an IO$_UNLOAD function, the drive can ; potentially be unloaded and therefore unable to accept the rewind command. ; Therefore, if UCB$L_RECORD contains a zero, and MT$M_LOST is not set don't ; perform a rewind. ; ; INPUTS: ; ; R2 - IRP address ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- IO_AVAILABLE: BICL #UCB$M_VALID,- ; Clear the volume valid bit in UCB$L_STS(R3) ; the UCB TSTL UCB$L_RECORD(R3) ; Is tape already at BOT? BNEQ 10$ ; Branch if not BBC #MT$V_LOST,- ; Branch if tape position not lost, OK UCB$L_DEVDEPEND(R3),20$ ; to skip rewind function 10$: MOVAL CMD_REWIND,R2 ; Get address of rewind command SETUP_CMD ; Setup the command MOVL SCDRP$L_CMD_PTR(R5),R1 ; Get the SCSI command address MOVB #1,4+SCSI_RWND$B_IMMED(R1) ; Set the immediate bit SEND_COMMAND_ORDERED ; Send the command BLBC R0,15$ ; Branch on error ADDL3 #MAX_REWIND_TIME,- ; Save time at which rewind must G^EXE$GL_ABSTIM,- ; be complete UCB$L_REWIND_TIME(R3) ; 15$: CLEANUP_CMD ; Cleanup from the SCSI command 20$: MOVZWL #SS$_NORMAL,R0 ; Set success status BISL #,- ; Mark beginning of tape UCB$L_DEVDEPEND(R3) ; BICL #,- ; and end of file UCB$L_DEVDEPEND(R3) ; CLRL UCB$L_RECORD(R3) ; Initialize record field MNEGL #2,UCB$L_PREV_TM(R3) ; No previous tape mark BRW COMPLETE_IO ; Complete this I/O function .PAGE .SBTTL IO_REWIND - Rewind the tape ;+ ; IO_REWIND ; ; This routine rewinds the tape. ; ; INPUTS: ; ; R2 - IRP address ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- IO_REWIND: BBS #IO$V_RETENSION,- ; Check to see if the RETENSION bit is SCDRP$L_FUNC(R5),25$ ; set - if so, branch to IO_RETENSION MOVAL CMD_REWIND,R2 ; Get address of rewind command SETUP_CMD ; Setup the command MOVL SCDRP$L_CMD_PTR(R5),R1 ; Get the SCSI command address BBC #IO$V_NOWAIT,- ; Branch if command should complete SCDRP$L_FUNC(R5),10$ ; only after tape finishes rewinding MOVB #1,4+SCSI_RWND$B_IMMED(R1) ; Set the immediate bit ADDL3 #MAX_REWIND_TIME,- ; Save time at which rewind must G^EXE$GL_ABSTIM,- ; be complete UCB$L_REWIND_TIME(R3) ; BISW #UCB$M_REWIND_INPROG,- ; Indicate rewind may be in progress UCB$L_MK_FLAGS(R3) ; when next QIO is issued 10$: SEND_COMMAND_ORDERED ; Send the command BLBC R0,20$ ; Branch on error BISL #,- ; Mark beginning of tape UCB$L_DEVDEPEND(R3) ; BICL #,- ; and end of file UCB$L_DEVDEPEND(R3) ; CLRL UCB$L_RECORD(R3) ; Tape is positioned at start MNEGL #2,UCB$L_PREV_TM(R3) ; No previous tape mark 20$: CLEANUP_CMD ; Cleanup from the SCSI command BRW COMPLETE_IO ; Complete this I/O function 25$: JMP IO_RETENSION ; BRANCH is out of range, uz JMP, .PAGE .SBTTL IO_DIAGNOSE - Special pass-through function ;+ ; IO_DIAGNOSE ; ; INPUTS: ; ; R2 - IPR address ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- IO_DIAGNOSE: PUSHAL UCB$PS_DIAGNOSE(R3) ; Address of DIAGNOSE area in UCB PUSHL R5 ; SCDRP address PUSHL SCDRP$L_CDT(R5) ; SCDT address PUSHL R2 ; IRP address CALLS #4,DKMK$DIAGNOSE_SIO ; Call common DIAGNOSE routine ; Quadword status is returned in R0. Get high longword of R0 into R1. EVAX_SRL R0,#32,R1 ; Return status in R0/R1 ; X-21 GWW BBC #UCB$V_CANCEL,- ; Branch if I/O has not been canceled UCB$L_STS(R5),5$ ; Otherwise, BRW COMPLETE_IO ; handle Cancelled one in the 5$: ; general IO completion routine MOVL R3,R5 ; KP_REQCOM requires UCB addr in R5 KP_REQCOM .PAGE .SBTTL + .SBTTL + SCSI COMMAND EXECUTION ROUTINES .SBTTL + .SBTTL INQUIRY - Send an inquiry command ;+ ; INQUIRY ; ; This routine sends an inquiry command to the target. The peripheral device ; type field is checked to make sure we do in fact have a SCSI tape device. In ; addition, the device type qualifier is used to determine if the device is a ; TZK50 or TZ30. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ;- INQUIRY: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH=,- PRESERVE= MOVAL CMD_INQUIRY,R2 ; Address of INQUIRY command SETUP_CMD ; Perform setup for SCSI command SEND_COMMAND_ORDERED ; Send the SCSI command BLBC R0,30$ ; Branch on error CMPL SCDRP$L_TRANS_CNT(R5),#5; Sufficient inquiry data returned? BLSSU 17$ ; Branch if not MOVL SCDRP$L_SVA_USER(R5),R0 ; Get address of inquiry data CMPL SCDRP$L_TRANS_CNT(R5),- ; Revision field valid? #36 ; BLSSU 10$ ; Branch if not MOVL 32(R0),UCB$L_HW_REV(R3) ; Save hardware revision level ASSUME UCB$B_DEVCLASS+1 EQ UCB$B_DEVTYPE 10$: CLRW UCB$B_DEVCLASS(R3) ; Assume unknown device class and type CMPB SCSI_INQ$B_DEVTYPE(R0),-; Is this a SCSI tape device? #SCSI$C_TAPE ; BNEQ 40$ ; Branch if not, illegal device type MOVB #DC$_TAPE,- ; Indicate that this a tape device UCB$B_DEVCLASS(R3) ; BBSS #UCB$V_REMOVABLE,- ; Assume drive has removable media UCB$L_MK_FLAGS(R3),15$ ; ASSUME SCSI_INQ$B_DEVTYPE+1 EQ SCSI_INQ$B_DEVQUAL ASSUME SCSI_INQ$V_REMOVABLE EQ 7 15$: TSTW (R0) ; Is this a removable media device? BLSS 20$ ; Branch if so BBCC #UCB$V_REMOVABLE,- ; Clear the removable media bit UCB$L_MK_FLAGS(R3),20$ ; in the UCB 17$: BRB 40$ ; 20$: EXTZV #0,#3,2(R0),R1 ; Get ANSI-approved version MOVB R1, UCB$B_SCSI_VERSION(R3) ; Save for future checks BEQL 25$ ; Does drive conform to SCSI-1? CMPB R1,#1 ; Does drive conform to CCS? BEQL 25$ ; Branch if so CMPB R1,#2 ; Does drive conform to SCSI-2? BEQL 25$ ; Yes LOG_ERROR - ; Log an invalid inquiry data error TYPE=INV_INQUIRY_DATA,- ; as a warning that we got unknown VMS_STATUS=#SS$_NORMAL,-; SCSI version - not a fatal error. UCB=R3 ; 25$: BSBW GET_DEVICE_TYPE ; Determine device type from Vendor 29$: MOVZWL #SS$_NORMAL,R0 ; Set success status 30$: CLEANUP_CMD ; Cleanup from the SCSI command RSB 40$: LOG_ERROR - ; Log an invalid inquiry data error TYPE=INV_INQUIRY_DATA,- ; VMS_STATUS=#SS$_NORMAL,-; UCB=R3 ; MOVZWL #SS$_DRVERR,R0 ; Set bad status BRB 30$ ; Use common exit .PAGE .SBTTL SKIP_RECORD - Move n records (in either direction) ;+ ; SKIP_RECORD ; ; This routine skips the number of records specified by the signed integer ; in R0. The operation is aborted if a tapemark is encountered. ; ; INPUTS: ; ; R0 - Signed word containing number of records skip ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1 - Actual number of records skipped ; UCB$L_RECORD - Updated ; R2 - Destroyed ;- SKIP_RECORD: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= BISB #UCB$M_SKIP_INPROG,- ; Indicate skip command in UCB$L_MK_FLAGS(R3) ; progress BICL #,- ; and end of file UCB$L_DEVDEPEND(R3) ; CVTWL R0,R0 ; Change word count to longword count BGEQ 5$ ; Branch if positive skip count BISB #UCB$M_REV_SKIP,- ; Indicate reverse motion in progress UCB$L_MK_FLAGS(R3) ; 5$: PUSHL R0 ; Save space count MOVAB CMD_SPACE,R2 ; Get address of SPACE command SETUP_CMD ; Setup the command ADDL3 #<4+SCSI_SKIP$B_CNT+3>,-; Get address just beyond count field SCDRP$L_CMD_PTR(R5),R1 ; in the SCSI command MOVL (SP),R0 ; Restore space count (but leave saved ; value on stack) .REPT 2 MOVB R0,-(R1) ; Copy two bytes of space count ASHL #-8,R0,R0 ; to the SCSI command .ENDR MOVB R0,-(R1) ; Copy the third byte CLRL UCB$L_ADDNL_INFO(R3) ; Initialize additional info field SEND_COMMAND_ORDERED ; Send the SCSI command CLEANUP_CMD ; Cleanup from the SCSI command POPL R1 ; Restore space count BLBC R0,20$ ; Branch on error 10$: BBS #UCB$V_NO_POSITION_UPDATE,- ; It is not appropriate to update UCB$L_MK_FLAGS(R3),15$ ; position now because IO_SKIP_FILE ; will ADDL R1,UCB$L_RECORD(R3) ; Update record number in UCB BGEQ 15$ ; Branch if non-negative record value BSBW SET_TAPE_LOST ; Otherwise, assume we are lost 15$: BICB #,- ; Indicate skip command no UCB$L_MK_FLAGS(R3) ; longer in progress RSB ; Return to caller ; Perform a sanity check on the additional info (residue) value returned by ; the tape. If the tape told us it skipped more records than we asked for ; then set tape position lost. Note that the residue field, like the skip ; count, is a signed longword. Therefore, in order to do the comparison, ; we have to distinguish between cases of skipping forward vs. reverse. 20$: MOVL UCB$L_ADDNL_INFO(R3),R2 ; Get number of unskipped records (residue) BBC #UCB$V_REV_SKIP,- ; Branch if original skip count was UCB$L_MK_FLAGS(R3),25$ ; positive (skipping forward) MNEGL R1,R1 ; Invert sign of requested skip count MNEGL R2,R2 ; Invert sign of residue BGEQ 25$ ; Branch if residue was negative MNEGL R2,R2 ; Otherwise, reinvert sign of residue MNEGL R2,UCB$L_ADDNL_INFO(R3) ; Save residue value as a negative 25$: CMPL R2,R1 ; Compare requested skip count with residue BLEQU 27$ ; Branch if residue is reasonable BSBW SET_TAPE_LOST ; Otherwise, assume we are lost BRB 15$ ; Use common exit 27$: BBC #UCB$V_REV_SKIP,- ; Branch if original skip count was UCB$L_MK_FLAGS(R3),29$ ; positive (skipping forward) MNEGL R1,R1 ; Otherwise, reinvert sign of requested skip count 29$: SUBL3 UCB$L_ADDNL_INFO(R3),- ; Get the actual number of records R1,R2 ; skipped ; If a tapemark was encountered, the actual skip count must be adjusted. This ; accounts for the fact that tape drives do not consider tapemarks to be ; records, but the software does (i.e., the UCB$L_RECORD field includes both ; normal records AND tapemarks). CMPL R0,#SS$_ENDOFFILE ; Tape mark encountered? BNEQ 30$ ; Branch if not INCL R2 ; Assume forward skipping TSTL R1 ; Was original skip count positive? BGEQ 30$ ; Branch if so SUBL #2,R2 ; Reverse skipping, fix up skip count 30$: MOVL R2,R1 ; Return actual space count in R1 BRB 10$ ; Use common exit .PAGE .SBTTL SKIP_FILE - Move n filemarks (in either direction) ;+ ; SKIP_FILE ; ; This routine skips the number of filemarks specified by the signed integer ; in R0. ; ; INPUTS: ; ; R0 - Signed word containing number of filemarks to skip ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1 - Actual number of filemarks skipped ; R2 - Destroyed ;- SKIP_FILE: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= BISL #,- UCB$L_MK_FLAGS(R3) ; BICL #,- ; and end of file UCB$L_DEVDEPEND(R3) ; CVTWL R0,R0 ; Change word count to longword count BGEQ 10$ ; Positive or negative space count? BISB #UCB$M_REV_SKIP,- ; Indicate reverse motion in progress UCB$L_MK_FLAGS(R3) ; 10$: PUSHL R0 ; Save space count MOVAB CMD_SPACE,R2 ; Get address of SPACE command SETUP_CMD ; Setup the command ADDL3 #<4+SCSI_SKIP$B_CNT+3>,-; Get address just beyond count field SCDRP$L_CMD_PTR(R5),R1 ; in the SCSI command MOVL (SP),R0 ; Restore space count (but leave saved ; value on stack) .REPT 2 MOVB R0,-(R1) ; Copy two bytes of space count ASHL #-8,R0,R0 ; to the SCSI command .ENDR MOVB R0,-(R1) ; Copy the third byte MOVB #1,-(R1) ; Filemarks code (from SCSI spec) CLRL UCB$L_ADDNL_INFO(R3) ; Initialize additional info field SEND_COMMAND_ORDERED ; Send the SCSI command CLEANUP_CMD ; Cleanup from the SCSI command POPL R1 ; Restore space count BLBC R0,20$ ; Branch on error BITL #,- ; Are we at either BOT or EOT? UCB$l_DEVDEPEND(R3) BNEQ 15$ ; Yes, so the correct DEVDEPEND bit was ; set already in TRANS_SENSE_KEY as ; the Check Condition was processed. BISL #MT$M_EOF,- ; Else, there was a success with no UCB$L_DEVDEPEND(R3) ; Check Condition, so the correct ; DEVDEPEND bit must be set now. 15$: BICL #,- UCB$L_MK_FLAGS(R3) ; RSB ; Return to caller ; Perform a sanity check on the additional info (residue) value returned by ; the tape. If the tape told us it skipped more files than we asked for ; then set tape position lost. Note that the residue field, like the skip ; count, is a signed longword. Therefore, in order to do the comparison, ; we have to distinguish between cases of skipping forward vs. reverse. 20$: MOVL UCB$L_ADDNL_INFO(R3),R2 ; Get number of unskipped files (residue) BBC #UCB$V_REV_SKIP,- ; Branch if original skip count was UCB$L_MK_FLAGS(R3),25$ ; positive (skipping forward) MNEGL R1,R1 ; Invert sign of requested skip count MNEGL R2,R2 ; Invert sign of residue BGEQ 25$ ; Branch if residue was negative MNEGL R2,R2 ; Otherwise, reinvert sign of residue MNEGL R2,UCB$L_ADDNL_INFO(R3) ; Save residue value as a negative 25$: CMPL R2,R1 ; Compare requested skip count with residue BLEQU 27$ ; Branch if residue is reasonable BSBW SET_TAPE_LOST ; Otherwise, assume we are lost BRB 15$ ; Use common exit 27$: BBC #UCB$V_REV_SKIP,- ; Branch if original skip count was UCB$L_MK_FLAGS(R3),29$ ; positive (skipping forward) MNEGL R1,R1 ; Otherwise, reinvert sign of requested skip count 29$: SUBL2 UCB$L_ADDNL_INFO(R3),- ; Get the actual number of files R1 ; skipped BRB 15$ ; Use common exit .PAGE .SBTTL RECEIVE_DIAG - Receive diagnostic results ;+ ; RECEIVE_DIAG ; ; This routine sends a RECEIVE DIAGNOSTIC RESULTS command to the tape ; to obtain the controller hardware and software revision levels for ; TZ30s and TK50s. The revision info is translated from hex to text and ; saved in the UCB. All other drives return revision information their ; inquiry data, and it is already in text format. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ;- DRIVER_DATA HEX_TO_TXT: .ASCII /0123456789ABCDEF/ DRIVER_CODE RECEIVE_DIAG: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH=,- PRESERVE= IF_TK 5$ ; Branch if device is a TZK50 or TZ30 MOVZWL #SS$_NORMAL,R0 ; Otherwise, this routine is a NOP RSB ; Return to caller 5$: MOVAL CMD_RECEIVE_DIAG,R2 ; Address of RECEIVE_DIAG command SETUP_CMD ; Perform setup for SCSI command MOVZWL #60,- ; Set up command-specific DMA timeout SCDRP$L_DMA_TIMEOUT(R5) SEND_COMMAND_ORDERED ; Send the SCSI command BLBC R0,10$ ; Branch on error CMPL SCDRP$L_TRANS_CNT(R5),#2; Sufficient diag data returned? BLSSU 20$ ; Branch if not MOVL SCDRP$L_SVA_USER(R5),R0 ; Get address of received diag data ASSUME SCSI_RCVD$B_HW_REV+1 EQ SCSI_RCVD$B_SW_REV MOVAL UCB$L_HW_REV(R3),R3 ; Get address of HW rev field in UCB MOVL #12,R1 ; Prepare to translate HW rev field 7$: EXTZV R1,#4,(R0),R2 ; Get a nibble of HW revision MOVB HEX_TO_TXT[R2],(R3)+ ; Translate to text and save in UCB SUBL #4,R1 ; Prepare to extract next nibble BGEQ 7$ ; Repeat for entire REV field MOVZWL #SS$_NORMAL,R0 ; Set success status 10$: CLEANUP_CMD ; Cleanup from the SCSI command RSB 20$: LOG_ERROR - ; Log an invalid diagnostic data error TYPE=DIAGNOSTIC_DATA,- ; VMS_STATUS=#SS$_NORMAL,-; UCB=R3 ; MOVZWL #SS$_DRVERR,R0 ; Set bad status BRB 10$ ; Use common exit .PAGE .SBTTL REQUEST_SENSE - Send a request sense command ;+ ; REQUEST_SENSE ; ; This routine is called by SEND_COMMAND when a command fails with check ; condition status. A REQEST SENSE command is sent to the target. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- REQUEST_SENSE: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH=,- PRESERVE= MOVAL CMD_REQUEST_SENSE,R2 ; Address of REQUEST_SENSE command SETUP_CMD ; Perform setup for SCSI command SPI$SEND_COMMAND ; Send the SCSI command BLBC R0,30$ ; Branch on SPI$SEND_COMMAND error ASSUME SCSI$C_GOOD_STATUS EQ 0 MOVZBL @SCDRP$L_STS_PTR(R5),R1 ; Get SCSI status byte BICB #SCSI$M_STAT_MASK,R1 ; Clear reserved, vendor unique bits BNEQ 20$ ; Branch if bad status 10$: RSB ; Return to caller 20$: MOVL #SS$_MEDOFL,R0 ; Set bad status 30$: LOG_ERROR - ; Log a send command error TYPE=SEND_CMD_ERROR,- ; VMS_STATUS=R0,- ; UCB=R3 ; BRB 10$ ; Clean up and return to caller .PAGE .SBTTL TEST_UNIT_READY - Send a test unit ready command ;+ ; TEST_UNIT_READY ; ; This routine sends a TEST UNIT READY command to the tape to determine ; whether the device is ready to receive read, write, and tape motion commands. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- TEST_UNIT_READY: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= BISB #UCB$M_WAITRDY_INPROG,- ; Set wait for unit ready in progress UCB$L_MK_FLAGS(R3) ; MOVAL CMD_TEST_UNIT_READY,R2 ; Address of TEST UNIT READY command SETUP_CMD ; Perform setup for SCSI command SEND_COMMAND_ORDERED ; Send the SCSI command CLEANUP_CMD ; Cleanup from the SCSI command BICB #UCB$M_WAITRDY_INPROG,- ; Clear wait for unit ready in progress UCB$L_MK_FLAGS(R3) ; RSB .PAGE .SBTTL MODE_SENSE - Send a mode sense command ;+ ; MODE_SENSE ; ; This routine sends a MODE SENSE command. The only mode sense information ; currently used is the write protect bit (bit 7 of the device-specific param) ; and (if it is available) the density from the first byte of the first block ; descriptor. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ;- MODE_SENSE: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH=,PRESERVE= ; Allocate a local copy of the mode page descriptors on the stack SUBL3 #DESCRIPTOR_SIZE,SP,R7 ; Size of descriptor array BICL #7,R7 ; Quadword align SUBL #DESCRIPTOR_SIZE+8,SP ; Account for desc + unalignment PUSHR #^M MOVC5 #0,.,#0,#DESCRIPTOR_SIZE,(R7) ; Initialize the desc area MOVC3 #DESCRIPTOR_SIZE,- ; Copy the descriptors DESCRIPTOR_BASE,(R7) POPR #^M PUSHL #0 ; Vendor specific page code PUSHAL VENDOR_UNIQUE_PAGE_DESC(R7) ; Address of descriptors PUSHL R5 ; SCDRP Address CALLS #3,DO_MODE_PAGE ; Process the page BLBC R0,50$ ; Branch on error BICL #MT$M_HWL,- ; Assume tape is not hardware write UCB$L_DEVDEPEND(R3) ; locked MOVL #VENDOR_UNIQUE_DEVSPC_DESC,R9 ; Offset to dev specific param ADDL2 R7,R9 ; Get address of dev specific descriptor BBC #7,MODE_DESC$L_ACTUAL(R9),20$ ; Is write-protect bit clear? BISL #MT$M_HWL,- ; Indicate that tape is in fact hardware UCB$L_DEVDEPEND(R3) ; write locked 20$: IFNOT_TSZ07 30$ ; Branch if not TSZ07 MOVL #VENDOR_UNIQUE_BDLEN_DESC,R9 ; Offset to block desc length ADDL2 R7,R9 ; Get address of blk desc len BBC #3,- ; Check for a block descriptor, MODE_DESC$L_ACTUAL(R9),- ; if none, leave 30$ CLRL R1 ; Clear in case default (0) density MOVL #VENDOR_UNIQUE_DENS_DESC,R9 ; Offset to block descriptor ADDL2 R7,R9 ; Get address of block desc MOVB MODE_DESC$L_ACTUAL(R9),- ; Get the current device density UCB$W_MK_DENSITY(R3) ; and save it BEQL 25$ ; If default (0), done tstw ucb$l_devdepnd3(r3) ;frontpanel bneq 25$ ADDW3 #2,UCB$W_MK_DENSITY(R3),- ; Translate to VMS density R1 ; 25$: INSV R1,#MT$V_DENSITY,- ; Store density in device #MT$S_DENSITY,- ; characteristics UCB$L_DEVDEPEND(R3) ; 30$: MOVZWL #SS$_NORMAL,R0 ; Set success status 40$: ADDL #DESCRIPTOR_SIZE+8,SP ; Account for desc + unalignment RSB 50$: ; Since DO_MODE_PAGE overwrote the SEND_COMMAND return status with SS$_NODATA ; whenever a bad SCSI status was returned, restore the SEND_COMMAND status ; for that case. Note: DO_MODE_PAGE propagates the SEND_COMMAND status ; for all other cases. CMPL #SS$_NODATA,R0 ; Do we need to restore status? BNEQ 40$ ; No, just exit MOVL UCB$L_SAV_SEND_STATUS(R3),R0 ; Restore status BRW 40$ .PAGE .SBTTL MODE_SELECT - Send a mode select command ;+ ; MODE_SELECT ; ; This routine sends a MODE_SELECT command to the tape to set up various drive ; characteristics including default block size, buffered (streaming) mode, ; number of fillers, and infinite reselection timeout. ; ; This command is different from others in that each device has its own ; vendor-unique data. At unit init, when the device type was determined, a ; pointer to this vendor-unique mode select data was placed in the UCB. This ; data is appended to the standard end of the standard mode select data. ; ; Rather than have a unique SCSI_CMD table entry for device type, we have ; a template entry containing the generic mode select data, and a seond entry ; used to actually build the mode select command. The template entry is first ; copied to the active entry, then the BCNT and parameter list length fields ; are increased by the length of the vendor-unique info length. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ;- MODE_SELECT: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH=,- PRESERVE= MOVAL CMD_MODE_SELECT_TMP,R1 ; Get the mode select command template MOVAL CMD_MODE_SELECT,R2 ; Get the mode select command PUSHR #^M ; Save regs MOVC3 #MODE_SEL_TMP_LEN,- ; Copy the mode select info from the (R1),(R2) ; template to the active command POPR #^M ; Restore regs MOVL UCB$L_MSEL_INFO(R3),R1 ; Get address of vendor-unique info MOVZBL (R1)+,R0 ; Get length of vendor-unique info ADDB R0,5(R2) ; Increase parameter list length in cmd ; by vendor-unique length ADDW R0,9(R2) ; Increase BCNT by vendor-unique length SUBL3 #DESCRIPTOR_SIZE,SP,R7 ; Size of descriptor array BICL #7,R7 ; Quadword align SUBL #DESCRIPTOR_SIZE+8,SP ; Account for desc + unalignment PUSHR #^M MOVC5 #0,.,#0,- #DESCRIPTOR_SIZE,(R7) ; Initialize the desc area MOVC3 #DESCRIPTOR_SIZE,- ; Copy the descriptors DESCRIPTOR_BASE,(R7) POPR #^M ; Assume no vendor unique info MOVAL BASIC_SELECT_DESC(R7),- R8 ; Address of descriptors 15$: MOVL UCB$L_MSEL_INFO(R3),R2 ; Get address of vendor-unique info MOVZBL (R2)+,R0 ; Get length of vendor unique info BNEQ 18$ ; If nonzero, go get it ; If here, then there is no vendor unique info. Set density if it's a TSZ07. tstw ucb$l_devdepnd3(r3) ; front panel active? bneq 12$ ; if neq insert density IFNOT_TSZ07 25$ ; If not a TSZ07, join common code brb 13$ 12$: movw ucb$l_devdepnd3(r3),UCB$W_MK_DENSITY(R3) 13$: ADDL3 - ; Get address of density descriptor #VENDOR_UNIQUE_SEL_DENS_DESC,- R7,R1 MOVB UCB$W_MK_DENSITY(R3),- ; Set desired density in descriptor MODE_DESC$L_DESIRED(R1) BRW 25$ ; Join common code to do Mode Select ; Yes, there is vendor unique info 18$: MOVAL (R7),R1 MULL3 #8,R0,(R1) ; Get bit size of vendor info MOVAL VENDOR_UNIQUE_SEL_DESC(R7),R8 ; Address of descriptors MOVAL (R7),R1 20$: MOVB (R2)+,(R1)+ ; Copy a byte of vendor-unique data SOBGTR R0,20$ ; Repeat for all vendor-unique data ; Common code 25$: PUSHL #0 ; Vendor specific page code PUSHL R8 ; Address of descriptors PUSHL R5 ; SCDRP Address CALLS #3,DO_MODE_PAGE ; Process the page BLBS R0,30$ ; MOVL #SS$_DRVERR,R0 ; Return error 30$: ADDL #DESCRIPTOR_SIZE+8,SP ; Account for desc + unalignment RSB .PAGE .SBTTL DO_8MM_COPY_CHK - 8mm COPY from BOT processing ;+ ; DO_8MM_COPY_CHK ; ; This routine is called from IO_WRITPBLK as a result of a SCSI error ; status returned in response to an attempt to begin a $COPY operation ; to a tape positioned at BOT and containing no files ($INIT done but ; tape void of files). ; ; During $COPY from BOT processing, the positioning command SPACE RECORD ; REVERSE is used to position the tape after the "VOL1..." record (1) and ; is followed by a WRITE command to write the "HDR1..." record (2). This is ; an illegal command sequence on the 8mm devices and results in CHECK ; CONDITION - ILLEGAL REQUEST status (SS$_DRVERR). ; ; To accommodate the 8mm behavior this routine creates an additional ; SCDRP and uses it and an S0 buffer to generate a REWIND, READ rec 1 ; ("VOL1..."), REWIND, WRITE rec 1 ("VOL1...") sequence to accomplish ; correct positioning for the write that follows the "VOL1..." record (1). ; ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1, R2 - Destroyed ; All other registers preserved ;- DO_8MM_COPY_CHK: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= MOVL R5,UCB$L_SCDRP_SAV1(R3) ; Save original SCDRP address MOVL SCDRP$PS_KPB(R5),- ; Save original KPB address UCB$L_KPB_SAV1(R3) MK_ALLOC_SCDRP ; Allocate additional SCDRP MOVL UCB$L_KPB_SAV1(R3),- ; Store KPB address in new SCDRP SCDRP$PS_KPB(R5) ; ; This seems to be the COPY from BOT situation...REWIND and ; READ the first record to determine if it is "VOL1...". ; BSBW DO_8MM_REWIND ; Do 1st Rewind BLBS R0,20$ ; Br if ok BRW 70$ ; Error status -- return 20$: MOVL SCDRP$L_CMD_BUF(R5),R0 ; Get address of command buffer SPI$CMD_BUFFER_DEALLOC ; Dealloc command buffer MOVAL CMD_READ_8MM,R2 ; Address of 8mm READ command SETUP_CMD ; Perform setup for SCSI command ADDL3 #<4+SCSI_RD$B_LEN+3>,- ; Get address just beyond transfer SCDRP$L_CMD_PTR(R5),R0 ; length field in the SCSI command MOVAL SCDRP$L_BCNT(R5),R1 ; Get addr of byte count field in SCDRP .REPT 3 MOVB (R1)+,-(R0) ; Fill in the transfer length .ENDR MOVL #IRP$M_FUNC,- ; Set the FUNC bit to indicate a READ SCDRP$IS_STS(R5) SEND_COMMAND_ORDERED ; Send the SCSI command BLBS R0,25$ ; Br if ok BRW 70$ ; Error status -- return 25$: CMPL @SCDRP$L_SVA_USER(R5),- ; Is this the "VOL1..." record #^A/VOL1/ BEQL 30$ ; Br if it is BRW 70$ ; It isn't -- just return 30$: SPI$BUFFER_UNMAP ; Un-map data buffer (but don't ; deallocate data buffer) MOVL SCDRP$L_CMD_BUF(R5),R0 ; Get address of command buffer SPI$CMD_BUFFER_DEALLOC ; Dealloc command buffer INCL UCB$L_RECORD(R3) ; Keep track of forward tape position ; ; Rewind again and WRITE "VOL1..." ; PUSHL SCDRP$L_BCNT(R5) ; Save the byte count for use by WRITE BSBW DO_8MM_REWIND ; Do 2nd Rewind BLBS R0,40$ ; Br if error POPL SCDRP$L_BCNT(R5) ; Restore the byte count BRB 70$ 40$: tstw ucb$l_devdepnd3(r3) ; front panel stuff active? beql 42$ bsbw mode_select ; select density again since at bot 42$: MOVL SCDRP$L_CMD_BUF(R5),R0 ; Get address of command buffer SPI$CMD_BUFFER_DEALLOC ; Dealloc command buffer ; ; The SCDRP still points to the S0 buffer containing the "VOL1..." ; record that was READ above, so WRITE it back to tape. Once this is ; done, subsequent WRITES will complete successfully. ; MOVAL CMD_WRITE_8MM,R2 ; Address of 8mm WRITE command SETUP_CMD ; Perform setup for SCSI command POPL SCDRP$L_BCNT(R5) ; Restore the byte count SPI$BUFFER_MAP PRIO=HIGH ; Re-map same user buffer used in READ ADDL3 #<4+SCSI_WRT$B_LEN+3>,- ; Get address just beyond transfer SCDRP$L_CMD_PTR(R5),R0 ; length field in the SCSI command MOVAL SCDRP$L_BCNT(R5),R1 ; Get addr of byte count field in SCDRP .REPT 3 MOVB (R1)+,-(R0) ; Fill in the transfer length .ENDR CLRL SCDRP$IS_STS(R5) ; Clr the FUNC bit to indicate a WRITE SEND_COMMAND_ORDERED ; Send the SCSI command BLBS R0,80$ ; Br if no error 70$: BSBW SET_TAPE_LOST ; Set position lost LOG_ERROR - ; Log an extended sense data error TYPE=EXTND_SENSE_DATA,- ; VMS_STATUS=#SS$_NORMAL,-; UCB=R3 ; MOVZWL #SS$_DRVERR,R0 ; Return error status 80$: INCL UCB$L_RECORD(R3) ; Keep track of forward tape position CLEANUP_CMD ; Cleanup from the SCSI command MK_DEACTIVATE_SCDRP - ; Deallocate the request sense SCDRP CLRSTK=YES MOVL UCB$L_SCDRP_SAV1(R3),R5 ; Restore original SCDRP MOVL R5,UCB$L_SCDRP(R3) ; copy to UCB 90$: CLRL UCB$L_8MM_CHK(R3) ; Clear COPY check in progress flag RSB .PAGE .SBTTL DO_8MM_REWIND - Rewind the 8MM device ;+ ; This subroutine is called from DO_8MM_COPY_CHK to send a rewind command to ; the device. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1, R2 - Destroyed ; All other registers preserved ;- DO_8MM_REWIND: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= MOVAL CMD_REWIND,R2 ; Address of REWIND command SETUP_CMD ; Setup the command SEND_COMMAND_ORDERED ; Send the command BLBC R0,20$ ; Br if error BISL #,- ; Mark the beginning of tape UCB$L_DEVDEPEND(R3) ; BICW #,- ; and end of file UCB$L_DEVDEPEND+2(R3) ; CLRL UCB$L_RECORD(R3) ; Tape is positioned at start MNEGL #2,UCB$L_PREV_TM(R3) ; No previous tape mark 20$: RSB .PAGE .SBTTL + .SBTTL + UTILITY ROUTINES .SBTTL + .SBTTL SET_UNIT_ONLINE - Issue SCSI commands to bring unit online ;+ ; SET_UNIT_ONLINE ; ; This routine attempts to bring a unit online. First, INQUIRY and RECEIVE ; DIAGNOSTIC RESULTS commands are sent to the drive to ensure that it can ; communicate, that it's a valid tape-like device, and that it's up to rev. ; A check is also done to see if the unit supports data compaction. ; If a failure occurs, a fork thread is set up to periodically poll the drive. ; ; INPUTS: ; ; R5 - UCB address ; ; OUTPUTS: ; ; R0-R5 - Destroyed ; ; ONLINE bit set in the UCB, BSY bit cleared ;- SET_UNIT_ONLINE: .JSB_ENTRY INPUT=,SCRATCH= 10$: MOVL UCB$L_PDT(R5),R4 ; Get PDT address MOVL R5,R3 ; Copy UCB address MK_ALLOC_SCDRP ; Allocate an SCDRP MOVL UCB$PS_UNITINIT_KPB(R3),- ; Save KPB address in SCDRP SCDRP$PS_KPB(R5) BISL2 #,- ; skipfile support and indicate UCB$L_MK_FLAGS(R3) ; initial READ POSITION pending BSBW INQUIRY ; Send an inquiry command BLBC R0,15$ ; Branch on error BSBW TEST_UNIT_READY ; Clear out a possible pending UNIT ; ATTENTION sense key BSBW RECEIVE_DIAG ; Send a receive diag data command BLBC R0,15$ ; Branch on error BSBW CHECK_COMPACTION_SUPPORT ; check if device supports data compaction BSBW CHECK_REV_LEVEL ; Check for minimum rev level MOVZWL #SS$_NORMAL,R0 ; Ignore revision check failure (bring ; drive online regardless of rev) 15$: MK_DEACTIVATE_SCDRP CLRSTK=YES ; Deallocate the SCDRP MOVL R3,R5 ; Copy UCB address BLBC R0,30$ ; Branch if error BISL #UCB$M_ONLINE!- ; Set the device online, busy UCB$M_BSY,- ; UCB$L_STS(R5) ; ; Since we don't know where the tape is at this point, initialize state in the ; UCB to indicate that position is lost. Normally the tape position is at BOT ; when the driver is loaded. However, it's possible that if we're booting ; standalone backup from tape, the position could be at some random point in ; the tape. Therefore, place it safe and assume we're lost. BSBW SET_TAPE_LOST ; Indicate we don't know where tape is .IF DEFINED DEBUG MOVL #SS$_NORMAL,R0 ; Set normal status BSBW TRACE_QIO_STAT ; Save the final QIO status in trace buf .ENDC REMQUE @UCB$L_IOQFL(R5),R3 ; Any I/O queued to this device? BVS 20$ ; Branch if not CALL_INITIATE ; Go initiate the I/O RSB 20$: BICL #UCB$M_BSY,- ; Clear the busy bit UCB$L_STS(R5) ; RSB ; Return to caller ; We've tried and failed at least once to send an inquiry command. Clear the ; online and busy bits and set up a fork thread to poll the device once ; a minute in an attempt to bring it online. In the meantime, any I/O queued to ; this device will fail with device offline status. Flush the queue of any I/O ; that might have been queued to the device during the period that it was ; online but busy. 30$: BICL #UCB$M_ONLINE,- ; Set the unit offline, but leave device UCB$L_STS(R5) ; busy since polling is in progress 40$: REMQUE @UCB$L_IOQFL(R5),R3 ; Remove an IRP from the queue BVS 45$ ; Branch if queue was empty INSQUE (R3),- ; Place on end of flush queue @UCB$L_FLUSH_IOQBL(R5) ; BRB 40$ ; Repeat until I/O queue is empty 45$: REMQUE @UCB$L_FLUSH_IOQFL(R5),-; Remove an IRP from the flush queue R3 ; BVS 50$ ; Branch if queue was empty MOVL R3,UCB$L_IRP(R5) ; Copy IRP addess to UCB MOVL #SS$_DEVOFFLINE,R0 ; Set device offline status CALL_REQCOM ; Complete the QIO BRB 45$ ; Continue to flush queue 50$: PUSHL UCB$B_FLCK(R5) ;F FF; Set the required fork lock PUSHAQ SIXTY_SECONDS ;F FF; Set the time delay in ticks PUSHL UCB$PS_UNITINIT_KPB(R5) ;F FF; Set the KPB address CALLS # 3, G^ EXE$KP_TQE_WAIT ;F FF; Fork and wait the desired time BRW 10$ ; And try again .PAGE .SBTTL SET_TAPE_LOST - Set state in UCB to indicate tape position lost ;+ ; SET_TAPE_LOST ; ; This routine sets state in thge UCB to indicate that the tape position is ; lost, and is called at unit init and any time are error occurs which causes ; us to suspect that we may have lost tape position. ; ; INPUTS: ; ; R3 - UCB ; ; OUTPUTS: ; ; MT$M_LOST set in DEVDEPEND of UCB ; MT$M_BOT, MT$M_EOT, MT$M_EOF cleared in DEVDEPEND of UCB ; UCB$L_PREV_TM gets -2 (no previous TM found) ; All registers preserved ;- SET_TAPE_LOST: .JSB_ENTRY INPUT= BITL #UCB$M_COMPCHK_IN_PROG,-; Compaction check in progress? UCB$L_MK_FLAGS(R3) ; BNEQ 10$ ; Skip set lost if yes BISL #MT$M_LOST,- ; Set position lost UCB$L_DEVDEPEND(R3) ; BICL #,- ; and end of file UCB$L_DEVDEPEND(R3) ; MNEGL #2,UCB$L_PREV_TM(R3) ; No previous tape mark 10$: RSB ; Return to caller .PAGE .SBTTL WAIT_UNIT_READY - Wait for unit to become ready ;+ ; WAIT_UNIT_READY ; ; This routine polls once every READY_POLL_INTERVAL seconds, waiting for the ; drive to become ready. The drive can be not ready for two reasons: a tape ; is not mounted in the drive; or a previous rewind/nowait command is still ; in progress. In SCSI, there's no way to distinguish between these two cases. ; However, the driver keeps track of the time that the last rewind command ; sent to the drive should have completed (in UCB$L_REWIND_TIME), and polling ; continues only until that time is exceeded. This prevents unnecessary polling ; when the tape drive is clearly not ready. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- WAIT_UNIT_READY: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= ; ready fails 10$: BSBW TEST_UNIT_READY ; Execute TEST UNIT READY command BLBC R0,30$ ; Branch on error 20$: BICL #UCB$M_UNLOAD_INPROG,- ; Clear UNLOAD bit UCB$L_MK_FLAGS(R3) RSB ; Return to caller 30$: CMPL R0,#SS$_DEVOFFLINE ; Device offline? BNEQ 20$ ; Branch if not MOVL #SS$_ABORT,R0 ; Assume I/O got canceled BBS #UCB$V_CANCEL,- ; Branch if it did UCB$L_STS(R3),20$ ; MOVZWL #SS$_MEDOFL,R0 ; Assume device is not ready BBS #UCB$V_UNLOAD_INPROG,- ; Branch if last operation was an UNLOAD UCB$L_MK_FLAGS(R3),35$ ; that we may be waiting for a media stacker CMPL G^EXE$GL_ABSTIM,- ; Could the not ready condition be UCB$L_REWIND_TIME(R3) ; due to a recent rewind command? BGEQU 20$ ; Branch if not, no need for more polling BRB 40$ ; Continue polling for rewind completion 35$: CMPL G^EXE$GL_ABSTIM,- ; Could the not ready condition be UCB$L_UNLOAD_TIME(R3) ; due to a recent unload operation? BGEQU 20$ ; Branch if not, no need for more polling 40$: PUSHL # SPL$C_IOLOCK8 ;F FF; Set the required fork lock PUSHAQ POLL_INTERVAL ;F FF; Set the time delay in ticks PUSHL SCDRP$PS_KPB(R5) ; Get address of KPB CALLS # 3, G^ EXE$KP_TQE_WAIT ;F FF; Fork and wait the desired time BRB 10$ ; Continue polling .PAGE .SBTTL CHECK_EOV - Check for logical end-of-volume ;+ ; CHECK_EOV ; ; This routine checks for logical end-of-volume, which has the following ; prerequisites: ; ; - Two consecutive tape marks are encountered during ; a SKIP_FILE or SKIP_RECORD operation ; ; If logical end-of-volume is detected, the tape is backspaced one record to ; position it between the two tapemarks. ; ; INPUTS: ; ; R0 - SS$_ENDOFVOLUME ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; UCB$L_RECORD - Current record (on which a tape mark has been found) ; UCB$L_PREV_TM - Record of last tapemark encountered ; ; OUPUTS: ; ; R0 - Status (SS$_ENDOFVOLUME or SS$_ENDOFFILE) ; R2 - Destroyed ; All other registers preserved ; ; UCB$L_PREV_TM - Updated ;- CHECK_EOV: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH=,PRESERVE= SUBL3 UCB$L_PREV_TM(R3),- ; Calculate difference between last UCB$L_RECORD(R3),-(SP) ; tapemark and this one. If consecutive, DECL (SP)+ ; then check for logical end-of-volume BNEQ 20$ ; Branch if not ; Logical end-of-volume detected. Position the tape between the two tapemarks ; by backspacing one record. MOVL #-1,R0 ; Prepare to back up one record BSBW SKIP_RECORD ; Position tape between filemarks CMPL R0,#SS$_ENDOFFILE ; EOF status? BNEQ 30$ ; Branch if not, serious problem exists MOVL #SS$_ENDOFVOLUME,R0 ; Return end of volume status 20$: MOVL UCB$L_RECORD(R3),- ; Update previous tapemark field in UCB$L_PREV_TM(R3) ; UCB with current record number 30$: RSB ; Return to caller .PAGE .SBTTL SEND_COMMAND - Send a SCSI command ;+ ; SEND_COMMAND ; ; This routines sends a command to the SCSI device. It returns any failing ; port status to the caller. If the port status is success, it checks the ; SCSI status byte. If a check condition status is returned, a request ; sense command is sent to the target and the sense key is translated into a ; VMS status code, which is returned as status. ; ; INPUTS: ; ; 4(AP) - UCB address ; 8(AP) - PDT address ; 12(AP) - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- SEND_COMMAND:: .CALL_ENTRY INPUT=<>,OUTPUT=,- SCRATCH=, PRESERVE= $ARG_DEF ; SCDRP Address MOVL ucb(AP),R3 ; MOVL pdt(AP),R4 ; MOVL scdrp(AP),R5 ; MOVB #BUSY_RETRY_CNT,- ; Initialize busy retry count UCB$B_BUSY_RETRY(R3) ; BICB #UCB$M_ADDNL_INFO,- ; Indicate additional info is not UCB$L_MK_FLAGS(R3) ; valid 1$: SPI$SEND_COMMAND ; Send the SCSI command BLBC R0,20$ ; Branch on error ASSUME SCSI$C_GOOD_STATUS EQ 0 MOVZBL @SCDRP$L_STS_PTR(R5),R1 ; Get SCSI status byte BICB #SCSI$M_STAT_MASK,R1 ; Clear reserved, vendor unique bits BNEQ 30$ ; Branch if bad status .IF DEFINED MULTI_VOLUME_TEST ; Code for testing multi-volume savesets MOVL UCB$L_IRP(R3),R1 ; Get IRP address BEQL 6$ ; Branch if not available EXTZV #IRP$V_FCODE,- ; Extract function code #IRP$S_FCODE,- ; IRP$L_FUNC(R1),R1 ; CMPL R1,#IO$_WRITEPBLK ; Write function? BEQL 5$ ; Branch if so CMPL R1,#IO$_WRITEOF ; Write tapemark? BNEQ 6$ ; Branch if not 5$: CMPL UCB$L_RECORD(R3),#^X50 ; Beyond artificial end of tape mark? BGEQU 40$ ; Branch if so 6$: .ENDC 10$: MOVL R0,UCB$L_SAV_SEND_STATUS(R3) ; Save status RET ; Return to caller ; The port returned bad status from SPI$SEND_CMD. Log an error and return to ; the caller. 20$: CMPL R0,#SS$_ABORT ; Aborted command? BEQL 10$ ; Branch if so, don't log an error LOG_ERROR - ; Log a send command error TYPE=SEND_CMD_ERROR,- ; VMS_STATUS=R0,- ; UCB=R3 ; BRB 10$ ; Use common exit ; A bad SCSI status code was returned. If the code is a check condition, then ; send a request sense command to the device. Otherwise, the status code is ; something unexpected. Log an error and return SS$_MEDOFL status. 30$: CMPB #SCSI$C_CHK_CONDITION,R1; Check condition status? BEQL 40$ ; Branch if so CMPB #SCSI$C_BUSY,R1 ; Device busy? BNEQ 35$ ; Branch if not BBC #UCB$V_WAITRDY_INPROG,- ; Branch if waiting for unit ready is UCB$L_MK_FLAGS(R3),35$ ; not in progress MOVL #SS$_DEVOFFLINE,R0 ; Return device off line status BRW 10$ ; Return to caller 35$: DECB UCB$B_BUSY_RETRY(R3) ; Decrement busy retry count BLEQ 37$ ; Branch if count expired PUSHL # SPL$C_IOLOCK8 ; Set the required fork lock PUSHAQ ONE_SECOND ; Set time delay PUSHL SCDRP$PS_KPB(R5) ; Set KPB address CALLS #3,G^EXE$KP_TQE_WAIT ; Fork and wait the desired time BRW 1$ ; Go send the command again 37$: LOG_ERROR - ; Log a send command error TYPE=SEND_CMD_ERROR,- ; VMS_STATUS=#SS$_NORMAL,-; UCB=R3 ; MOVL #SS$_MEDOFL,R0 ; Return a generic status code BRW 10$ ; Return to caller ; A check condition status code was returned. Save the original SCDRP address ; allocate a second one and send a request sense command. If the request ; sense succeeds, translate the sense key to a VMS status code and return that ; as the status code for the original command. 40$: TSTL UCB$L_8MM_CHK(R3) ; If an 8mm COPY check flag is set, BNEQ 10$ ; Return to caller CLRB SCDRP$B_SENSE_KEY(R5) ; Initialize saved sense key field ; Handle the case of invalid autosense data. BBS #SCDRP$V_FLAG_ASENSE_VALID, - ; Is the autosense data valid ? SCDRP$L_SCSI_FLAGS(R5), 45$ ; Yes, continue CLRL SCDRP$L_SVA_USER(R5) ; Else set up for reg dump rtn LOG_ERROR - ; Log an extended sense data error TYPE=EXTND_SENSE_DATA,- VMS_STATUS=#SS$_NORMAL,- UCB=R3 CLRL SCDRP$PS_PREV_SCDRP(R5) ; No additional SCDRP MOVL #SS$_DRVERR,R0 ; Return general failure BRW 10$ ; Return 45$: MOVL SCDRP$L_SVA_USER(R5),R6 ; Save user buffer address MOVL SCDRP$L_TRANS_CNT(R5),R7 ; Save transfer count MOVL SCDRP$PS_SENSE_BUFFER(R5),- ; Copy Auto Sense buffer address SCDRP$L_SVA_USER(R5) ; to User buffer address ; The length field is byte 7 of the sense data and represents the number ; of bytes after itself. So add 8 to get total length. Note: Trans_cnt is ; needed by the register dump routine. MOVL SCDRP$L_SVA_USER(R5),R0 ; Sense data address MOVZBL SCSI$SNS$B_ADD_SENSE_LEN(R0),R0 ; Addn sense length ADDL3 #1,#SCSI$SNS$B_ADD_SENSE_LEN,R1 ; Preceding bytes ADDL3 R1,R0,SCDRP$L_TRANS_CNT(R5) ; Total sense length BSBW LOG_EXTND_SENSE ; Log an extended sense error MOVL R7,SCDRP$L_TRANS_CNT(R5); Restore transfer count BSBW SAVE_ADDNL_INFO ; Save any valid additional information ; from the extended sense data BSBW TRANS_SENSE_KEY ; Translate the extended sense key to ; a VMS status code in R0 MOVL R6,SCDRP$L_SVA_USER(R5) ; Restore user buffer address BRW 10$ ; Return to caller .PAGE .SBTTL LOG_EXTND_SENSE - Log an extended sense data error ;+ ; LOG_EXTND_SENSE ; ; This routine logs an extended sense data error. ; ; Certain errors are suppressed including: ; ; - UNIT ATTENTIONS (we can't tell the difference between device resets ; and media changes, so we log nothing) ; ; - A NOT READY sense key. ; ; Before logging the error, play a trick with the two SCDRPs currently in use. ; Since we're really interested in logging the contents of the original command, ; and not the request sense command, copy the address of the original command ; buffer into the SCDRP for the request sense command. This causes the contents ; of the original command (a read or write, for example) to be logged along ; with the contents of the request sense data returned from the request sense ; command. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; ; OUTPUTS: ; ; R0-R2 - Destroyed ; All other registers preserved ;- LOG_EXTND_SENSE: .JSB_ENTRY INPUT=,SCRATCH=,PRESERVE= MOVL SCDRP$L_SVA_USER(R5),R0 ; Get address of extended sense data MOVZBL 12(R0),R7 ; Get ASC MOVZBL 13(R0),R8 ; Get ASQ BITB #SCSI_XS$M_ILI,- ; Illegal length indicator? SCSI_XS$B_KEY(R0) ; BNEQ 10$ ; Branch if so BITB #,- ; End of medium? SCSI_XS$B_KEY(R0) ; BEQL 5$ ; Branch if not ; The following sequence checks that a skip record operation which encounters ; a tape mark, BOT, or EOT returns valid additional info (residue) from the ; subsequent request sense command. If not, the driver has no way of keeping ; track of the UCB$L_RECORD value. BBC #UCB$V_SKIP_INPROG,- ; Branch if skip command not in UCB$L_MK_FLAGS(R3),4$ ; progress ASSUME SCSI_XS$V_ADDNL_VALID EQ 7 TSTB SCSI_XS$B_ERR_CODE(R0) ; Valid additional info? BGEQ 7$ ; Branch if not 4$: BRB 10$ ; Otherwise, leave without logging an error 5$: EXTZV #SCSI_XS$V_KEY,- ; Get the extended sense key #SCSI_XS$S_KEY,- ; SCSI_XS$B_KEY(R0),R1 ; BEQL 10$ ; Branch if no sense data CMPB R1,- ; Unit attention sense key? #SCSI$C_UNIT_ATTENTION ; BEQL 10$ ; Branch if so, don't log an error CMPB R1,#SCSI$C_NOT_READY ; Device not ready sense key? BEQL 10$ ; Branch if so, don't log an error 7$: MOVL SCDRP$L_CMD_PTR(R5),R2 ; Save address of request sense cmd MOVB #SCSI$C_CHK_CONDITION,- ; Original command failed with request @SCDRP$L_STS_PTR(R5) ; sense status ; ; If this is an 8mm device we may have arrived here as a result of the ; SPACE REC REV - WRITE SCSI command sequence which $COPY from BOT processing ; generates. That command sequence is illegal on the 8mm and results ; in a CHECK CONDITION - ILLEGAL REQUEST error response from the device. ; DO_8MM_COPY_CHK will subsequently generate an alternate SCSI command sequence ; that will recover from the error and accommodate the 8mm behavior. ; IFNOT_8MM 700$ ; Br if not 8MM CMPB R1,- ; Illegal Request sense key? #SCSI$C_ILLEGAL_REQUEST BNEQ 700$ ; Br if not Illegal Request BBC #DEV$V_MNT,- ; Br if not mounted UCB$L_DEVCHAR(R3),8$ BBS #DEV$V_FOR,- ; Br if mounted foreign UCB$L_DEVCHAR(R3),8$ MOVL UCB$L_IRP(R3),R1 ; Restore IRP address EXTZV #IRP$V_FCODE,- ; Extract I/O function code #IRP$S_FCODE,- ; IRP$L_FUNC(R1),R1 ; CMPB #IO$_WRITEPBLK,R1 ; Write in progress? BNEQ 8$ ; Br if not CMPL #1,UCB$L_RECORD(R3) ; Br if the record # is not consistent BNEQ 8$ ; with the $COPY from BOT error MOVL #1,UCB$L_8MM_CHK(R3) ; Set COPY check in progress flag BRB 9$ ; Go to return 700$: CMPB R1,#SCSI$C_BLANK_CHECK ; Check for blank-check error and BOT, BNEQ 8$ BBS #UCB$V_SPACEFILE_INPROG,- ; Suppress if SPACE FILEMARKS just UCB$L_MK_FLAGS(R3),9$ ; hit logical EOV TSTL UCB$L_RECORD(R3) ; Supress logging error since it is - BEQL 9$ ; new tape. mcy 8/28/92 ; Don't log certain Illegal Request errors that can result from sending ; e.g. a READ POSITION command to a target that does not support it. 8$: CMPL R1,#SCSI$C_ILLEGAL_REQUEST ; Illegal command sense key? BNEQ 36$ ; No, so log it BBS #UCB$V_READPOSCHK_IN_PROG,- ; Is READ POSITION check in progress? UCB$L_MK_FLAGS(R3),9$ ; If so, don't log error 36$: LOG_ERROR - ; Log an extended sense data error TYPE=EXTND_SENSE_DATA,- ; VMS_STATUS=#SS$_NORMAL,-; UCB=R3 ; 9$: MOVL R2,SCDRP$L_CMD_PTR(R5) ; Restore address of request sense cmd 10$: RSB ; Return to caller .PAGE .SBTTL TRANS_SENSE_KEY - Translate extended sense key to VMS status code ;+ ; TRANS_SENSE_KEY ; ; This routine translates an extended sense key to a VMS status code using ; SENSE_KEY_TABLE. If the sense key is not found in the table (indicating an ; invalid sense key), then a generic VMS status code (SS$_MEDOFL) is returned. ; ; The filemark and EOM bits generate status codes of SS$_ENDOFFILE and ; SS$_ENDOFTAPE respectively. ; ; Certain situations cause an additional translation including: ; ; - If the sense key was NOT_READY and the wait for unit ready flag is set in ; the UCB, then this is an indication that the device is in the process of ; becoming ready. Return a DEVOFFLINE status to allow the WAIT_UNIT_READY ; routine to continue to poll for unit ready. Otherwise, change the ; status to SS$_MEDOFL to cause mount verification to occur for this device. ; ; - Any medium error which does not have an additional sense code of ; non-recoverable ECC error generates SS$_DRVERR status. This is considered ; "more fatal" as it could cause us to lose tape position. ; ; INPUTS: ; ; R3 - UCB address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - VMS status code ; R1,R2 - Destroyed ; All other registers perserved ;- TRANS_SENSE_KEY: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= MOVL SCDRP$L_SVA_USER(R5),R2 ; Get address of request sense data .IF DEFINED MULTI_VOLUME_TEST ; Code for testing multi-volume savesets MOVL UCB$L_IRP(R3),R1 ; Get IRP address BEQL 3$ ; Branch if not available EXTZV #IRP$V_FCODE,- ; Extract function code #IRP$S_FCODE,- ; IRP$L_FUNC(R1),R1 ; CMPL R1,#IO$_WRITEPBLK ; Write function? BEQL 2$ ; Branch if so CMPL R1,#IO$_WRITEOF ; Write tapemark? BNEQ 3$ ; Branch if not 2$: CMPL UCB$L_RECORD(R3),#^X50 ; Beyond artificial end of tape mark? BLSSU 3$ ; Branch if not BISB #^X40,2(R2) ; Simulate end of tape 3$: .ENDC ; If the key is recorvered error or no sense, then go ahead and look at the ; EOF, EOM, and ILI flags in the extended sense data. Any other type of sense ; key takes precedence over these flags. ASSUME SCSI_XS$S_KEY EQ 4 EXTZV #SCSI_XS$V_KEY,- ; Get the extended sense key #SCSI_XS$S_KEY,- ; SCSI_XS$B_KEY(R2),R1 ; ASSUME SCSI$C_NO_SENSE EQ 0 BEQL 4$ ; Branch if no sense CMPB R1,- ; Recovered error? #SCSI$C_RECOVERED_ERROR ; BEQL 4$ ; Branch if so CMPB R1,#SCSI$C_BLANK_CHECK ; End of data? BNEQ 35$ ; No, continue BBC #UCB$V_SPACEFILE_INPROG,- ; SPACE FILEMARKS in progress? UCB$L_MK_FLAGS(R3),35$ MOVL #SS$_ENDOFVOLUME,R0 ; Yes, just hit EOV BISL #MT$M_EOF,- ; and is at a tapemark UCB$L_DEVDEPEND(R3) BRW 80$ ; Workaround for a bug in the TK50: if this is a medium error sense key and the ; EOM bit is set, then this indicates we're at BOT or EOT and the medium error ; sense key can be ignored. 35$: CMPB R1,- ; Medium error? #SCSI$C_MEDIUM_ERROR ; BNEQ 6$ ; Branch if not IFNOT_TK50 6$ ; Branch if not a TK50 4$: BITB #SCSI_XS$M_ILI,- ; Illegal length indicator? SCSI_XS$B_KEY(R2) ; BNEQ 90$ ; Branch if so BITB #SCSI_XS$M_EOF,- ; Filemark? SCSI_XS$B_KEY(R2) ; BNEQ 50$ ; Branch if so BITB #SCSI_XS$M_EOM,- ; End of medium? SCSI_XS$B_KEY(R2) ; BNEQ 60$ ; Branch if so ; If this is a UNIT ATTENTION sense key, the volume valid bit is NOT set ; in the UCB, and the "wait for unit ready" bit is set, then return success. ; This situation can occur for multi-volume tape backups when one tape is ; unloaded and the next is loaded. We'll eventually need a PACACK to make the ; drive usable. 6$: CMPB R1,- ; Unit attention sense key? #SCSI$C_UNIT_ATTENTION ; BNEQ 5$ ; Branch if not BBS #UCB$V_VALID,- ; Branch if volume valid bit is set UCB$L_STS(R3),5$ ; in the UCB BBC #UCB$V_WAITRDY_INPROG,- ; Branch if NOT waiting for unit ready UCB$L_MK_FLAGS(R3),5$ ; MOVZWL #SS$_NORMAL,R0 ; Set success status BRB 40$ ; Use common exit path 5$: MOVB R1,SCDRP$B_SENSE_KEY(R5); Save sense key in the SCDRP MOVAL SENSE_KEY_TABLE,R0 ; Get address of sense key to VMS status ; code translation table MOVL (R0)[R1],R0 ; Pick up VMS error code ; A status code of SS$_DRVERR indicates a serious error occurred. If this is ; the case, set the tape position lost. 25$: CMPL R0,#SS$_DRVERR ; Serious error? BNEQ 26$ ; Branch if not BSBW SET_TAPE_LOST ; Set tape lost ; The following code allows the routine WAIT_UNIT_READY to poll for unit ; ready. If a NOT_READY sense key is returned by the drive, and the wait for ; unit ready flas is set, then return DEVOFFLINE status to notify the caller ; that the device is still not ready, Otherwise, return MEDOFL status to ; cause mount verification to kick in. 26$: CMPL R0,#SS$_DEVOFFLINE ; Device offline status? BNEQ 40$ ; Branch if not BBS #UCB$V_WAITRDY_INPROG,- ; Branch if waiting for unit ready is UCB$L_MK_FLAGS(R3),40$ ; set ; ; Notify MME that the device is unavailable and allow them to correct ; if possible. ; MOVL #MME$_UNLOAD, R0 ; load MME event code. PUSHL R5 ; save the CDRP address on the stack. MOVL R3, R5 ; copy the UCB address into R5. JSB G^MME$$DEV_EVENT ; invoke the MME call-out routine. POPL R5 ; restore the CDRP address. 30$: MOVZWL #SS$_MEDOFL,R0 ; Otherwise, set medium offline status 40$: RSB ; Return to caller ; EOF set. This indicates a filemark was encountered during the previous tape ; motion command. Set SS$_ENDOFFILE status and set the EOF bit in the device ; dependent field. 50$: MOVZWL #SS$_ENDOFFILE,R0 ; Assume filemark (end of file) BISL #,- ; Set end of file bit in UCB UCB$L_DEVDEPEND(R3) ; BRB 80$ ; Perform sanity check on additional ; info (if skip record in progress) ; EOM set. This indicates that the tape reached one end or the other, based ; on the direction of motion. In the case of reverse motion, BOT is set. ; Otherwise, EOT is set. In either case, ENDOFTAPE status is returned. 60$: MOVL #,R1 ; Assume reverse motion BBS #UCB$V_REV_SKIP,- ; Branch if reverse motion in UCB$L_MK_FLAGS(R3),70$ ; progress MOVL #,R1 ; Prepare to set end of tape 70$: BISL R1,UCB$L_DEVDEPEND(R3) ; Set BOT/EOT based on current direction MOVL #SS$_ENDOFTAPE,R0 ; Set end of tape status ; If the original command was a skip record, and no valid additional info was ; returned, then set a fatal error status and mark the tape position as lost, ; as we need the additional info to keep track of our position on the tape. 80$: BBC #UCB$V_SKIP_INPROG,- ; Branch if skip command not in UCB$L_MK_FLAGS(R3),40$ ; progress BBS #UCB$V_ADDNL_INFO,- ; Branch if valid additional info UCB$L_MK_FLAGS(R3),40$ ; returned IF_TSZ05 40$ ; For TSZ05 and TSZ07 devices, skip rev IF_TSZ07 40$ ; doesn't return "addl info" flag set. MOVL #SS$_DRVERR,R0 ; Otherwise, change to fatal error BSBW SET_TAPE_LOST ; Set tape position lost BRB 40$ ; Use common exit ; ILI set. This indicates that the requested record length did not match the ; actual record length on tape. If the record on tape was shorter than the ; requested length, ignore the ILI bit as utility doing the read does not ; necessarily know ahead of time the length of the record on tape. If the ; record on tape was longer than the requested length, return a data overrun ; status code. The data overrun condition is detected by the ILI bit being ; set and a TRANS_CNT equal to BCNT. It's assumed that the drive would have ; returned more data if the host had requested it. 90$: MOVZWL #SS$_NORMAL,R0 ; Assume no data overrun CMPW SCDRP$L_TRANS_CNT(R5),- ; Data overrun condition? SCDRP$L_BCNT(R5) ; BLSSU 40$ ; Branch if not MOVZWL #SS$_DATAOVERUN,R0 ; Return data overrun status BRB 40$ .PAGE .SBTTL SAVE_ADDNL_INFO - Save additional extended sense information ;+ ; SAVE_ADDNL_INFO ; ; This routine is called whenever valid extended sense data is returned by a ; target to obtain any addition data. In the case of a skip command, ; this information is used later to determine the actual number of records or ; files skipped. ; ; INPUTS: ; ; R3 - UCB address ; R5 - SCDRP address associated with request sense command ; ; OUTPUTS: ; ; R0,R1 - Destroyed ; ; UCB$L_ADDNL_INFO - Additional info field from the extended ; sense data or -1 if no valid data. ;- SAVE_ADDNL_INFO: .JSB_ENTRY INPUT=,SCRATCH= MOVL SCDRP$L_SVA_USER(R5),R0 ; Get address of request sense data MOVAL UCB$L_ADDNL_INFO(R3),R1 ; Get address of additional info field CLRL (R1) ; Assume additonal info not valid ASSUME SCSI_XS$V_ADDNL_VALID EQ 7 TSTB SCSI_XS$B_ERR_CODE(R0) ; Valid additional info? BGEQ 30$ ; Branch if not BISB #UCB$M_ADDNL_INFO,- ; Indicate additional info is valid UCB$L_MK_FLAGS(R3) ; MOVAL SCSI_XS$B_ADDNL_INFO+4(R0),R0 ; Get address just beyond ; additonal info field .REPT 4 MOVB -(R0),(R1)+ ; Copy a byte of additional info from ; the extended sense data to the UCB. ; (Note that bytes are reversed in the ; extended sense data). .ENDR 30$: RSB .PAGE .SBTTL INIT_SCDRP - Initialize an SCDRP ;+ ; INIT_SCDRP ; ; This routine initializes an SCDRP which has already been allocated on the ; kernel process stack. The entire SCDRP is zero'ed and various fields ; are initialized. ; ; INPUTS: ; ; R3 - UCB address ; R5 - SCDRP address ; ; OUTPUTS: ; ; UCB$L_SCDRP - SCDRP address ; SCDRP$L_UCB - UCB address ; SCDRP$B_FLCK - Fork lock ; SCDRP$L_CDT - CDT address ; SCDRP$L_SCSI_FLAGS - Initialized ;- INIT_SCDRP: .JSB_ENTRY INPUT=,PRESERVE= PUSHR #^M ; Save regs MOVC5 #0,(SP),#0,- ; Initialize the SCDRP #SCDRP$C_LENGTH-12,- ; 12(R5) ; POPR #^M ; Restore regs MOVL R5,UCB$L_SCDRP(R3) ; Save SCDRP address in UCB MOVL R3,SCDRP$L_UCB(R5) ; Save UCB address in SCDRP MOVB UCB$B_FLCK(R3),- ; Copy the fork lock field from the SCDRP$B_FLCK(R5) ; UCB to the SCDRP MOVL UCB$L_SCDT(R3),- ; Save CDT address in SCDRP SCDRP$L_CDT(R5) ; MOVW #SCDRP$K_LENGTH, - ; Setup SCDRP length field SCDRP$W_SCDRPSIZE(R5) MOVB #DYN$C_SCDRP, - ; Setup SCDRP structure type SCDRP$B_CD_TYPE(R5) RSB .PAGE .SBTTL GET_DEVICE_TYPE - Determine device type from inquiry data ;+ ; GET_DEVICE_TYPE ; ; This routine translates the product ID field from the INQUIRY data to ; a VMS device type. In addition, it fills in the media ID field in the UCB. ; The TZK50 and TZ30 are handled specially, since these devices have no product ; ID field in the inquiry data. For the TZK50 and TZ30, there is exactly 5 ; bytes if inquiry data, and the device qualifier fields contain 50 (hex) and ; 30 (hex), respectively. ; ; INPUTS: ; ; R0 - Address of INQUIRY data ; R3 - UCB address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R1 - Destroyed ; All other registers preserved ;- GET_DEVICE_TYPE: .JSB_ENTRY INPUT=,SCRATCH=,PRESERVE= CMPL SCDRP$L_TRANS_CNT(R5),#5; 5 bytes of inquiry data? BNEQ 20$ ; Branch if not, can't be a TK50 or TZ30 EXTZV #SCSI_INQ$V_DEVQUAL,- ; Get device type qualifier #SCSI_INQ$S_DEVQUAL,- ; SCSI_INQ$B_DEVQUAL(R0),-; R1 ; ; Check for device type of TZ30 CMPB R1,#^X30 ; TZ30? BNEQ 10$ ; Branch if not MOVAL TZ30_DEV_TYPE,R1 ; Get table entry for TZ30 BRB 60$ ; Check for device type of TZK50 10$: CMPB R1,#^X50 ; TZK50? BNEQ 20$ ; Branch if not MOVAL TK50_DEV_TYPE,R1 ; Get table entry for TK50 BRB 60$ ; Branch to common code ; Device is not a TZ30 or TK50. Scan the device type table to see if we have ; a matching produce ID field. If not, then treat this device as a generic SCSI ; tape. 20$: CMPL SCDRP$L_TRANS_CNT(R5),- ; Enough inquiry data to have a valid #24 ; produce ID field? BLSS 50$ ; Branch if not MOVAL SCSI_DEVICE_TABLE,R1 ; Get SCSI device table 30$: CMPL DTYP_ID_LOW(R1),16(R0) ; Matching product ID (low LW)? BNEQ 40$ ; Branch if not CMPL DTYP_ID_HIGH(R1),20(R0) ; Matching product ID (high LW)? BEQL 60$ ; Branch if so 40$: ADDL #DTYP_TABLE_ENTRY_SIZE,- R1 ; Advance to next entry in table TSTB DTYP_TYPE(R1) ; End of table BNEQ 30$ ; Branch if not ; Device is not a TZ30 or TK50, nor was a matching product ID field found in ; the device type tape. Treat the device as a generic SCSI tape. 50$: MOVAL GENERIC_DEV_TYPE,R1 ; Get table entry for generic tape 60$: MOVB DTYP_TYPE(R1),- ; Save VMS device type UCB$B_DEVTYPE(R3) MOVL DTYP_MINREV(R1),- ; Save minimum revision level UCB$L_MIN_REV(R3) BBC #DTYP$V_NO_SKIPFILE,- ; Should skipfile be avoided? DTYP_FLAGS(R1),62$ BICL2 #UCB$M_SKIPFILE_SUPPORTED,- ; Yes, so disable skip-by-file UCB$L_MK_FLAGS(R3) 62$: BBC #DEV$V_DTN,- ; If DTN bit is set, remove the dynamic UCB$L_DEVCHAR2(R3),65$ ; name PUSHR #^M ; Save registers across call PUSHL R3 ; ioc$remove_device_type(&ucb) CALLS #1,G^IOC$REMOVE_DEVICE_TYPE POPR #^M ; Restore registers ; 65$: MOVL DTYP_MEDIA_ID(R1),- ; Save media ID field UCB$L_MEDIA_ID(R3) ; MOVAB DTYP_VENDOR(R1),- ; Save address of vendor-unique mode UCB$L_MSEL_INFO(R3) ; select info BBS #MT2$V_COMP_ENA, - ; Compaction enabled ? UCB$L_DEVDEPND2(R3), 64$; INSV DTYP_DENSITY(R1),- ; Save density information #MT$V_DENSITY,- ; #MT$S_DENSITY,- ; UCB$L_DEVDEPEND(R3) ; 64$: BBC #DTYP$V_LOADER,- DTYP_FLAGS(R1),67$ ; Check for loader device - mcy/rcl 9/18 BISL2 #DEV$M_LDR,- ; Set loader bit if device is loader UCB$L_DEVCHAR2(R3) ; 67$: BICL #UCB$M_DEVICE_IS_8MM,- ; Assume not an 8mm device UCB$L_MK_FLAGS(R3) CMPL #^A/EXB-/, 16(R0) ; Is it an EXABYTE tape (8mm)? BEQL 68$ ; Branch if so CMPL #^A/TKZ0/,16(R0) ; Is it a TKZ09? BNEQ 70$ CMPL #^A/9 /,20(R0) BNEQ 70$ ; Branch if not 68$: BISL #UCB$M_DEVICE_IS_8MM,- ; Set "it's an 8mm device" flag UCB$L_MK_FLAGS(R3) ; ; At this point: ; R0 = Address of the inquiry data ; R3 = UCB ; R5 = SCDRP ; 70$: CMPB #DT$_GENERIC_MK,- ; Did we find this device in the table? UCB$B_DEVTYPE(R3) BNEQ 80$ ; Yes, don't do dynamic naming CMPL SCDRP$L_TRANS_CNT(R5),- ; A proper INQUIRY response is at least #32 ; 32 bytes. Do we have that? BLSS 80$ ; Nope, can't do dynamic naming ; ; At this point: ; R0 = Address of the inquiry data ; R3 = UCB ; ; Register usage: ; R0 = input name pointer ; R1 = output name pointer ; R2 = original SP ; R4 = end of field pointer ; R5 = "last character was a blank" flag ; R6 = scratch ; ; First, process the Vendor ID, compressing multiple blanks into one. ; MOVL SP,R2 ; Save stack pointer CLRL R5 ; Initialize "last was blank" flag BICL #7,SP ; Quad align the stack SUBL #32,SP ; Allocate space for name and such MOVL SP,R1 ; Setup pointer into name buffer MOVAB 8(R0),R0 ; Point to vendor ID MOVAB 8(R0),R4 ; Vendor ID is 8 bytes long 301$: CMPL R0,R4 ; End of field? BEQL 320$ ; Yes, continue with product ID CMPB #^X20,(R0)+ ; Is character a blank BNEQ 302$ ; No, clear flag and copy BLBS R5,301$ ; If previous char blank, skip this one MOVL #1,R5 ; Otherwise, set "last was blank" flag MOVB #^X20,(R1)+ ; and store a blank BRB 301$ ; Back for next character 302$: CLRL R5 ; Clear "last was blank" flag MOVB -1(R0),(R1)+ ; and copy the character BRB 301$ ; Back for next character ; ; Now, setup to process the product ID. Again, compress multiple blanks ; into one. Also, the copyright symbol "(C)" or "(c)" is treated as a ; name terminator. ; 320$: MOVAB 16(R0),R4 ; Product ID is 16 bytes long BLBS R5,321$ ; If trailing blank on Vendor, continue MOVL #1,R5 ; Otherwise, insert a blank between MOVB #^X20,(R1)+ ; vendor and product IDs 321$: CMPL R0,R4 ; See if we have a full type name BEQL 330$ ; Yes, we're done CMPB #^X20,(R0)+ ; Is the next character a blank? BNEQ 322$ ; No, go check for copyright BLBS R5,321$ ; If previous char blank, skip this one MOVL #1,R5 ; Otherwise, set "last was blank" flag MOVB #^X20,(R1)+ ; and store a blank BRB 321$ ; Back for next character ; ; Check for copyright... ; 322$: CMPB #^A/(/,-1(R0) ; Was character a "(" BNEQ 323$ ; Nope, go copy it BICB3 #^X20,(R0),R6 ; Convert next char to upper case CMPB #^A/C/,R6 ; See if it's a "C" BNEQ 323$ ; Nope, just copy data CMPB #^A/)/,1(R0) ; Look for closing paren BEQL 330$ ; Found copyright, so we're done 323$: CLRL R5 ; Clear "last was blank" flag MOVB -1(R0),(R1)+ ; and copy the character BRB 321$ ; Back for next character 330$: SUBL3 SP,R1,R0 ; Calculate name length SUBL R5,R0 ; Remove any trailing blank PUSHAL 28(SP) ; Add dynamic name: PUSHL R3 ; status = ioc$add_device_type( PUSHL R0 ; &name, namelen, &ucb &(&dtn)) PUSHAB 12(SP) ; (Buffer is now under 3 longword args) CALLS #4,G^IOC$ADD_DEVICE_TYPE MOVL R2,SP ; Clean the stack 80$: RSB ; Return to caller .PAGE .SBTTL CHECK_REV_LEVEL - Check for an out-of-rev device ;+ ; CHECK_REV_LEVEL ; ; This routine checks the revision level returned in the INQUIRY or RECEIVE ; DIAGNOSTIC data with the minimum revision level for that device. If the ; device's revision level is below the minimum allowed, an invalid inquiry ; data error is logged. ; ; Note: since the revision field in the inquiry data is a 4 byte ascii string, ; the low-order byte is the most significant. Thus, the bytes must be compared ; from low byte to high byte, and a CMPL can not be used to perform the ; comparison. ; ; INPUTS: ; ; R3 - UCB address ; UCB$L_HW_REV - Revision level ; UCB$L_MIN_REV - Minimum revision level ; ; OUTPUTS: ; ; R0 - Status (LBS if rev level OK) ; R1,R2 - Destroyed ; All other registers preserved ; An error is logged of the device is out-of-rev ;- CHECK_REV_LEVEL: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH=,- PRESERVE= CLRL R0 ; Assume out of rev MOVAL UCB$L_HW_REV(R3),R1 ; Get addr of actual revision level MOVAL UCB$L_MIN_REV(R3),R2 ; Get addr of minimum revision level .REPT 4 CMPB (R1)+,(R2)+ ; Compare a byte of revision level BLSSU 20$ ; Branch if out of rev BGTRU 5$ ; Branch if rev OK .ENDR 5$: MOVL #SS$_NORMAL,R0 ; Set success status 10$: RSB ; Return to caller 20$: LOG_ERROR - ; Log an invalid inquiry data error TYPE=INV_INQUIRY_DATA,- ; VMS_STATUS=#SS$_NORMAL,-; UCB=R3 ; BRB 10$ ; Use common exit .PAGE .SBTTL MK_ALLOC_POOL - Allocate a block of non-paged pool ;+ ; MK_ALLOC_POOL ; ; This routine was formerly called ALLOC_POOL and was renamed to reflect ; the new meaning of R5 as an input (now KPB address, not SCDRP address). ; ; This routine allocates a block of non-paged pool no smaller than the ; size of a fork block (allowing COM$DRVDEALMEM to fork on this block ; during deallocation). An extra quadword at the top of the block is reserved ; to save the size field, relieving the caller this responsibility. The caller ; is presented with the address just beyond the reserved quadword. Although a ; word would be sufficient for this field, a quadword is used for allignment ; purposes (some blocks are used as IRPs, which are placed on self-relative ; queues and require quadword allignment). ; ; If an allocation failure occurs, the thread is stalled and wakes up once a ; a second to retry the allocation. ; ; INPUTS: ; ; R1 - Size of block to allocate ; R3 - UCB address ; R5 - KPB address ; ; OUTPUTS: ; ; R0 - Output status ; R1 - Size of block allocated ; R2 - Address of allocated block ; -8(R2) - Length of allocated block (used by DEALLOC_POOL) ; All other registers perserved ;- MK_ALLOC_POOL: .JSB_ENTRY INPUT=,OUTPUT=,PRESERVE= ADDL #8,R1 ; Reserve a quadword to save size CMPL R1,#FKB$C_LENGTH ; Requested size smaller than fork block? BGEQ 10$ ; Branch if not MOVL #FKB$C_LENGTH,R1 ; Use fork block size as minimum 10$: PUSHL R1 ; Save allocation length JSB G^EXE$ALONONPAGED ; Allocate a block BLBC R0,20$ ; Branch if error ADDL #4,SP ; Remove allocation length from stack PUSHR #^M ; Save regs MOVC5 #0,(SP),#0,R1,(R2) ; Initialize the packet POPR #^M ; Restore regs MOVL R1,(R2)+ ; Save size of block ADDL #4,R2 ; Skip a longword RSB ; Return to caller ; A pool allocation failure occurred. Come back once a second and retry the ; operation until successful. 20$: PUSHL UCB$B_FLCK(R3) ;F FF; Set the required fork lock PUSHAQ ONE_SECOND ;F FF; Set the time delay in ticks PUSHL R5 ;F FF; Set the KPB address CALLS # 3, G^ EXE$KP_TQE_WAIT ;F FF; Fork and wait the desired time POPL R1 ; Restore allocation length BRW 10$ ; Try again .PAGE .SBTTL DEALLOC_POOL - Deallocate a block of non-paged pool ;+ ; DEALLOC_POOL ; ; This routine deallocates a block of non-paged pool. The size of the block ; is stored in the reserved quadword at a negative offset from the beginning ; of the block. ; ; INPUTS: ; ; R0 - Address of block to deallocate ; -8(R0) - Length of block to deallocate ; ; OUTPUTS: ; ; R0 - Destroyed ; All other registers perserved ;- DEALLOC_POOL: .JSB_ENTRY INPUT=,SCRATCH=,PRESERVE= SUBL #4,R0 ; Skip a longword MOVL -(R0),IRP$W_SIZE(R0) ; Copy size field CLRB IRP$B_TYPE(R0) ; Clear type field (prevents block from ; being interpreted as shared memory ; during deallocation) JSB G^EXE$DEANONPAGED ; Deallocate the block RSB .PAGE .SBTTL SETUP_CMD - Common setup for all SCSI commands ;+ ; SETUP_CMD ; ; This routine performs common setup prior to the sending of a SCSI command. ; This includes allocating a command buffer, filling in the pointers in the ; SCDRP to the command and status fields, copying the SCSI command to the command ; buffer, allocating an S0 "user" buffer if the command requires transferring ; data to or from the class driver, filling in the SCDRP fields used to map ; this buffer, and mapping the buffer. ; ; Since this routine calls SPI$CMD_BUFFER_ALLOC, which can suspend ; the thread, the return PC must be saved in the SCDRP. ; ; INPUTS: ; ; 4(AP) - Pointer to entry in SCSI_CMD table ; 8(AP) - UCB address ; 12(AP) - PDT address ; 16(AP) - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; ; SCDRP$L_CMD_BUF - Address of SCSI command buffer ; SCDRP$L_CMD_PTR - Address of SCSI command ; SCDRP$L_STS_PTR - Address to save SCSI status byte ; SCDRP$L_SVA_USER- Address of S0 "user" buffer ; SCDRP$L_BCNT - Length of S0 "user" buffer ; SCDRP$L_BOFF - Byte offset of S0 "user" buffer ; SCDRP$L_SVAPTE - SVAPTE of of S0 "user" buffer ; IRP$V_FUNC - SET/CLEAR to indicate READ/WRITE from S0 "user" buffer ;- SCSI_CMD_BUF_OVHD = 4 + 4 ; 4 bytes to save status byte + ; 4 bytes for SCSI command length SETUP_CMD:: ; Common setup for all SCSI commands .CALL_ENTRY INPUT=<>,OUTPUT=,SCRATCH=,- PRESERVE= $ARG_DEF ; SCDRP Address MOVL cmd(AP),R2 ; MOVL ucb(AP),R3 ; MOVL pdt(AP),R4 ; MOVL scdrp(AP),R5 ; MOVZBL (R2),R1 ; Get size SCSI command ADDL #SCSI_CMD_BUF_OVHD,R1 ; Add in command buffer overhead PUSHL R2 ; Save R2 SPI$CMD_BUFFER_ALLOC ; Allocate a command buffer MOVL R2,R1 ; Copy command buffer address POPL R2 ; Restore R2 MOVB #^XFF,(R1) ; Initialize status field MOVAL (R1)+,- ; Address to put SCSI status byte SCDRP$L_STS_PTR(R5) ; MOVL R1,SCDRP$L_CMD_PTR(R5) ; Save address of SCSI command MOVZBL (R2)+,R0 ; Get SCSI command length MOVL R0,(R1)+ ; Save length in command buffer ; The PUSHAB and BISB2 instructions are used to fill in the LUN field in the ; command packet. SCSI-2 suggests that this field be left with a zero and ; that message handshaking between the port driver and target convey LUN ; information. Therefore, these two instructions have been commented out. ;** PUSHAB 1(R1) ; Save address of SCSI command LUN field ASHL #-1,R0,R0 ; Change byte count to word count 10$: MOVW (R2)+,(R1)+ ; Copy a byte of SCSI command SOBGTR R0,10$ ; Repeat for entire SCSI command ;** BISB UCB$B_LUN(R3),@(SP)+ ; Fill in SCSI LUN field MOVZWL (R2)+,- ; Set up command-specific timeout value SCDRP$L_DISCON_TIMEOUT(R5) CVTWL (R2),R1 ; Get length of send data buffer BLSS 20$ ; Branch if negative, no system buffer ; involved, leave SCDRP$L_BCNT unchanged BEQL 30$ ; Branch if zero length, zero SCDRP$L_BCNT BBC - ; Did we already allocate a buffer? #SCDRP$V_FLAG_CL_PRIVATE_BUFF,- SCDRP$L_SCSI_FLAGS(R5),15$ MOVL SCDRP$L_SVA_USER(R5),R1 ; Get start address of buffer ADDL #2,R2 ; Skip over length BRW 18$ ; Branch to common code 15$: PUSHL R2 ; Save R2 PUSHL R5 ; Save SCDRP address MOVL SCDRP$PS_KPB(R5),R5 ; Get KPB address BSBW MK_ALLOC_POOL ; Allocate a buffer to receive response POPL R5 ; Restore SCDRP address MOVL R2,R1 ; Copy buffer address POPL R2 ; Restore R2 MOVL R1,SCDRP$L_SVA_USER(R5) ; Save address of allocated buffer MOVZWL (R2)+,SCDRP$L_BCNT(R5) ; Save length of transfer 18$: CLRL SCDRP$L_PAD_BCNT(R5) ; No padding required INSV (R2),#IRP$V_FUNC,#1,- ; Set/clear FUNC bit to indicate READ/ SCDRP$IS_STS(R5) ; WRITE function MOVL G^MMG$GL_BWP_MASK,R2 ; Mask of BWP portion of virtual address EVAX_AND R1,R2,R2 ; Get byte offset within page MOVL R2,SCDRP$L_BOFF(R5) ; Save byte offset PUSHL R3 ; Save R3 MOVL SCDRP$L_SVA_USER(R5),R2 ; Get user buffer address JSB G^MMG$SVAPTECHK ; Get SVAPTE of allocated system buffer MOVL R3,SCDRP$L_SVAPTE(R5) ; Save SVAPTE in SCDRP POPL R3 ; Restore R3 BISB #SCDRP$M_FLAG_S0BUF!- ; This buffer is an S0 "user" buffer SCDRP$M_FLAG_BUFFER_MAPPED,-; and it has been mapped SCDRP$L_SCSI_FLAGS(R5) ; SPI$BUFFER_MAP PRIO=HIGH ; Map the "user" buffer for read access 20$: MOVZWL #SS$_NORMAL,R0 ; Set success status RET 30$: CLRL SCDRP$L_BCNT(R5) ; No data being transferred BRB 20$ ; Use common exit .PAGE .SBTTL CLEANUP_CMD - Common cleanup for all SCSI commands ;+ ; CLEANUP_CMD ; ; This routine performs common cleanup after the sending of a SCSI command ; including unmapping the user buffer and deallocating the command buffer. ; ; INPUTS: ; ; 4(AP) - PDT address ; 8(AP) - SCDRP address ; ; OUTPUTS: ; ; R2 - Destroyed ; All other registers preserved ;- CLEANUP_CMD:: .CALL_ENTRY INPUT=<>,SCRATCH=,PRESERVE= $ARG_DEF ;S FF: SCDRP Address MOVL pdt(AP),R4 ; MOVL scdrp(AP),R5 ; BBCC #SCDRP$V_FLAG_BUFFER_MAPPED,-; Branch if no buffer has been mapped SCDRP$L_SCSI_FLAGS(R5),-; 10$ SPI$BUFFER_UNMAP ; Unmap the mapped buffer 10$: BBCC #SCDRP$V_FLAG_S0BUF,- ; Branch if this is not an S0 "user" SCDRP$L_SCSI_FLAGS(R5),-; buffer 20$ ; MOVL SCDRP$L_SVA_USER(R5),R0 ; Get address of S0 user buffer CLRL SCDRP$L_SVA_USER(R5) ; Buffer no longer owned BBS - ; Private buffer to be handled by other code #SCDRP$V_FLAG_CL_PRIVATE_BUFF,- SCDRP$L_SCSI_FLAGS(R5),20$ BSBW DEALLOC_POOL ; Deallocate the buffer 20$: MOVL SCDRP$L_CMD_BUF(R5),R0 ; Get address of command buffer SPI$CMD_BUFFER_DEALLOC ; Deallocate the command buffer 30$: RET .PAGE .SBTTL LOG_ERROR - Write an entry to the errorlog file ;+ ; LOG_ERROR ; ; This routine writes an entry to the errorlog file. If the device is offline, ; no error is logged. This prevents the errorlog file from being filled up while ; the class driver does it its periodic polling of devices that have been set ; offline. The assumption is that the initial error that caused the device to ; be placed offline has been logged and that subsequent errorlog entries would ; be redundent. ; ; If the device class and/or type fields in the UCB have not been initialized, ; then fill in "TAPE" and "GENERIC SCSI TAPE" respectively so the packet can be ; properly formatted by ERF. This situation could arise if invalid inquiry data ; is received for the device, preventing these fields from being filled in ; properly. ; ; If no I/O is active for this device (for example, if an error is detected ; during unit initialization) log a device attention. Otherwise, log a ; device error and then release the errorlog entry. This prevents errors from ; being lost if multiple errors are logged for a single QIO. ; ; Some types of errors are logged just once per system boot. For example, if ; invalid mode sense data is returned by the target, just one INVALID_SENSE_DATA ; error is logged to prevent filling the errorlog with duplicate packets. The ; DUPLICATE_ERR_MASK table specifies those error types which should be logged ; just once. A bitmask in the UCB records those error types that have been ; logged already. ; ; INPUTS: ; ; R5 - UCB address ; ; OUTPUTS: ; ; All registers preserved ;- DRIVER_DATA DUPLICATE_ERR_MASK: ; Bitmask of error types that can .LONG - ; be logged more than once <1@SCSI$C_MAP_BUFFER_ERROR>!- <1@SCSI$C_SEND_CMD_ERROR>!- <1@SCSI$C_EXTND_SENSE_DATA>!- <1@SCSI$C_REASSIGN_BLOCK> DRIVER_CODE LOG_ERROR: .JSB_ENTRY INPUT=,PRESERVE= BBS #UCB$V_DISABL_ERRLOG,- ; Branch if errlogging is disabled UCB$L_MK_FLAGS(R5),35$ BBC #UCB$V_ONLINE,- ; Branch if device is offline (don't UCB$L_STS(R5),35$ ; log an error) MOVL UCB$L_ERROR_TYPE(R5),R7 ; Save error type BBCS R7,UCB$L_ERR_MASK(R5),- ; Branch if this error type has not 5$ ; been logged yet BBC R7,DUPLICATE_ERR_MASK,- ; Branch if this is a type of error 35$ ; that should be logged just once 5$: BSBW FILTER_ERROR ; OK to filter error? BLBS R0,35$ ; Branch if so MOVB UCB$B_DEVTYPE(R5),R9 ; Save SCSI device type BNEQ 10$ ; Branch if device type known MOVB #DT$_GENERIC_MK,- ; Fill in generic type so ERF can UCB$B_DEVTYPE(R5) ; translate the errlog packet ; The following code segment temporarily replaces the values TK50 and TZ30 ; with TK50S and TZ30S, respectively. This allows ERF to distinguish errlog ; packets logged by this driver from those logged by the VS2000 driver. 10$: IF_TZ30 11$, R5 ; Branch if this is a TZ30 IFNOT_TK50 12$, R5 ; Branch if this is not a TK50 MOVB #DT$_TK50S,- ; Change TK50 to TK50S UCB$B_DEVTYPE(R5) BRB 12$ ; Join common path 11$: MOVB #DT$_TZ30S,- ; Change TZ30 to TZ30S UCB$B_DEVTYPE(R5) ; 12$: MOVB UCB$B_DEVCLASS(R5),R10 ; Save DEVCLASS field MOVB #DC$_TAPE,- ; Temporarily set this field to a tape UCB$B_DEVCLASS(R5) ; so ERF can translate packet MOVL UCB$L_DDT(R5),R0 ; Get DDT address MOVW SCSI_ERROR_LEN_TAB-2[R7],-; Save required errorlog packet size DDT$W_ERRORBUF(R0) ; in the DDT TSTL UCB$L_IRP(R5) ; I/O in progress? BEQL 20$ ; Branch if not CALL_DEVICERR SAVE_R0R1=NO ; Log a device error BBCC #UCB$V_ERLOGIP,- ; Clear error log in progress. UCB$L_STS(R5),30$ ; MOVL UCB$L_EMB(R5),R2 ; Get address of error message buffer BEQL 30$ ; Branch if none available ; The following four fields are normally filled in by IOC$REQCOM, but such ; code does not execute when UCB$V_ERLOGIP is clear, so we do it here: MOVL UCB$L_STS(R5),- ; Insert final device status. EMB$L_DV_STS(R2) ; MOVL UCB$L_ERTCNT(R5),- ; Insert final error counters. EMB$L_DV_ERTCNT(R2) ; MOVL UCB$L_ERTMAX(R5),- ; Insert final error counters. EMB$L_DV_ERTMAX(R2) ; CLRQ EMB$Q_DV_IOSB(R2) ; Insert zero I/O status, since we ; cannot know IOSB at this point. CALL_RELEASEMB ; Realease the errorlog buffer BRB 30$ ; Skip no-I/O-in-progress path 20$: CALL_DEVICEATTN SAVE_R0R1=NO ; Log a device attention 30$: MOVB R10,UCB$B_DEVCLASS(R5) ; Restore original devclass value MOVB R9,UCB$B_DEVTYPE(R5) ; Restore device type 35$: RSB ; Return to caller .PAGE .SBTTL FILTER_ERROR - Attempt to filter error ;+ ; FILTER ERROR ; ; This routine attempts to filter the current error being logged by ; checking to see if the same error has been logged recently. If so, ; don't log it again. This prevents the errlog file from filling up ; if the same error is occurring repeatedly. ; ; An array in the UCB contains the last n errors logged. Each error is ; timestamped so that eventually it will go stale and a duplicate ; error will be logged. ; ; INPUTS: ; ; R5 - UCB address ; R7 - Error type ; ; UCB$L_SCDRP - Active SCDRP address ; ; OUTPUTS: ; ; R0 - Status (LBS if error can be filtered) ;- FILTER_ERROR: .JSB_ENTRY INPUT=,OUTPUT=,PRESERVE= IFNOT_TK LABEL=45$,UCB=R5 ; Branch if not a TK50 or TZ30, can't ; try to filter ; First, assemble the information for the current error in R1 as follows: ; ; +-------+------+---------------+ ; | MBZ | ASC | KEY | ERR | ; +-------+------+---------------+ ; ; ERR - Error code ; KEY - Sense key (extended sense data errors only) ; ASC - Additional sense key (extended sense data errors only) ; ; This will be used later to compare against the entries in the error array ; and to save information for this error if it's not being fioltered. MOVZBL R7,R1 ; Copy error type CMPL R7,- ; Extended sense data error? #SCSI$C_EXTND_SENSE_DATA; BNEQ 10$ ; Branch if not MOVL UCB$L_SCDRP(R5),R0 ; Get SCDRP address BEQL 10$ ; Branch if no SCDRP active TSTL SCDRP$L_TRANS_CNT(R0) ; Extended sense data available? BEQL 10$ ; Branch if not MOVL SCDRP$L_SVA_USER(R0),R0 ; Get address extended sense BEQL 10$ ; Branch if none available INSV SCSI_XS$B_KEY(R0),- ; Get sense key #8,#8,R1 INSV SCSI_XS$B_ADDNL_CODE30(R0),- ; Get additional sense code #16,#8,R1 ; CMPB SCSI_XS$B_KEY(R0),- ; Recovered error? #SCSI$C_RECOVERED_ERROR ; BEQL 45$ ; Yes, don't filter it CMPB SCSI_XS$B_KEY(R0),- ; Medium error? #SCSI$C_MEDIUM_ERROR ; BEQL 45$ ; Yes, don't filter it ; Next, scan the error array to see if an identical error has already ; been logged. 10$: MOVL #2,R3 ; Number of entries in error array MOVAL UCB$B_ERR_ARRAY(R5),R2 ; Get address of error array 20$: CMPL (R2),G^EXE$GL_ABSTIM ; Stale entry? BLSSU 30$ ; Branch if so CMPL R1,4(R2) ; Matching error? BEQL 60$ ; Branch if so, OK to filter ADDL #8,R2 ; Advance to next entry in array SOBGTR R3,20$ ; Repeat for all entries in array ; This error was not found in the array. Push all the entries in the array ; down (the array is ordered on expiration time) and add this error to the ; array. 30$: MOVL #2-1,R3 ; Number of entries in array less 1 MOVAQ UCB$B_ERR_ARRAY(R5)[R3],R2 ; Get address just beyond error array 40$: MOVL -(R2),8(R2) ; Push an entry down in the array MOVL -(R2),8(R2) SOBGTR R3,40$ ; Repeat for entire array ADDL3 #60,G^EXE$GL_ABSTIM,- ; Set expiration time for new entry (R2)+ ; to one minute from now MOVL R1,(R2) ; Save new entry 45$: CLRL R0 ; Can't filter this entry 50$: RSB ; Return to caller 60$: MOVL #1,R0 ; This error can be filtered BRB 50$ ; Use common exit .PAGE .SBTTL SET_CONN_CHAR - Modify connection characteristics ;+ ; SET_CONN_CHAR ; ; This routine is called at the end of PACKACK to initialize the connection ; characteristics, which specify such things as whether the device supports ; disconnect and synchronous operation, and the bus busy, arbitration, and ; selection retry counters. ; ; This routine first allocates a connection characteristics buffer on the ; kernel process stack, then calls SPI$CONNECTION_CHAR_GET to get the current ; values of the connection characteristics, modifies the values of interest, ; and calls SPI$CONNECTION_CHAR_SET to set up the new values. This allows ; the class driver to change a subset of the characteristics and leave the ; rest unmodified. ; ; INPUTS: ; ; R3 - UCB address ; R4 - SPDT address ; R5 - SCDRP address ; ; OUTPUTS: ; ; R0 - Status ; R1,R2 - Destroyed ; All other registers preserved ;- SET_CONN_CHAR: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= SUBL #SPI$K_CC_LENGTH,SP ; Allocate buffer on the KP stack MOVL SP,R2 ; Copy buffer address MOVL #SPI$K_CC_NUM_ARGS,- ; Set argument count in buffer SPI$IL_CC_COUNT(R2) SPI$CONNECTION_CHAR_GET ; Get current connection characteristics BLBC R0,10$ ; Branch on error ASSUME SET_CON$M_DISC EQ 1 EXTZV #UCB$V_DISCONNECT,#1,- ; Fill in disconnect flag UCB$L_MK_FLAGS(R3),- ; SET_CON$L_CON_FLAGS(R2) ; BISL #SET_CON$M_NORETRY,- ; Disable port driver command retry SET_CON$L_CON_FLAGS(R2) ; ASSUME SET_CON$M_SYN EQ 1 EXTZV #UCB$V_SYNCHRONOUS,#1,- ; Fill in synchronous flag UCB$L_MK_FLAGS(R3),- ; SET_CON$L_SYN_FLAG(R2) ; SPI$CONNECTION_CHAR_SET ; Set the connection characteristics 10$: ADDL #SPI$K_CC_LENGTH,SP ; Clear buffer off the stack BLBS R0,20$ ; Branch if success status MOVL #SS$_CTRLERR,R0 ; Otherwise, return a reasonable status 20$: RSB ; Return to caller .PAGE .SBTTL CHECK_SKIPFILE_SUPPORT - Check if device supports READ POSITION command ;+ ; CHECK_SKIPFILE_SUPPORT ; ; This routine is called by IO$_PACKACK code in order to determine whether ; the device supports the READ POSITION command. If it does, then the ; ucb$l_mk_flags bit SKIPFILE_SUPPORTED will be set. That bit is later ; checked when doing IO$_SKIPFILE operations; if READ POSITION is supported, ; a skipfiles operation may be done most efficiently by sending a Space ; Filemarks to advance the tape, followed by a Read Position to obtain ; position information needed to fill in ucb$l_record. ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUPUTS: ; ; R0 - Status ; R1,R2 - destroyed ;- CHECK_SKIPFILE_SUPPORT: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= BBC #UCB$V_SKIPFILE_SUPPORTED,- ; If cmd was previously declared UCB$L_MK_FLAGS(R3),40$ ; unsupported, don't even try. MOVAL CMD_READ_POSITION,R2 ; Address of READ POSITION command SETUP_CMD ; Perform setup for SCSI command BISL #UCB$M_READPOSCHK_IN_PROG,- ; Set READ POSITION chk-in-prog UCB$L_MK_FLAGS(R3) SEND_COMMAND_ORDERED ; Send the SCSI command BICL #UCB$M_READPOSCHK_IN_PROG,- ; Clear READ POSITION chk-in-prog UCB$L_MK_FLAGS(R3) BLBC R0,20$ ; Branch on error CMPL SCDRP$L_TRANS_CNT(R5),- ; Sufficient data returned? #20 ; READ POS data len should equal 20 BLSS 20$ ; No, so declare cmd unsupported MOVL SCDRP$L_SVA_USER(R5),R0 ; Get address of data BBS #BPU_BIT,- ; If block position unknown, (R0),20$ ; declare the command unsupported ; Sanity check: the value just returned should equal UCB$L_RECORD. MOVAB 8(R0),R0 ; Prepare to get READ POS value MOVAB UCB$L_RECORD(R3),R1 ; Prepare to get UCB$L_RECORD .REPT 4 CMPB -(R0),(R1)+ ; Compare READ POS, UCB$L_RECORD BNEQ 20$ ; If unequal, declare READ POS .ENDR ; cmd to be unsupported BISL2 #UCB$M_SKIPFILE_SUPPORTED,- ; READ POSITION command supported UCB$L_MK_FLAGS(R3) 30$: CLEANUP_CMD ; Clean up command 40$: MOVL #SS$_NORMAL,R0 ; Always return success BICL #UCB$M_FIRST_READPOS_CMD,- ; The first one is done UCB$L_MK_FLAGS(R3) RSB ; Error path: READ POSITION cannot be supported. 20$: BICL2 #UCB$M_SKIPFILE_SUPPORTED,- ; READ POSITION command unsupported UCB$L_MK_FLAGS(R3) BBS #UCB$V_FIRST_READPOS_CMD,- ; Suppress logging the very first UCB$L_MK_FLAGS(R3),30$ ; one (eg. for devices that do not ; support the READ POSITION cmd) LOG_ERROR - TYPE=SEND_CMD_ERROR,- VMS_STATUS=#SS$_NORMAL,- UCB=R3 BRW 30$ ; Common exit .PAGE .SBTTL CHECK_COMPACTION_SUPPORT - Check if device supports data compaction ;+ ; CHECK_COMPACTION_SUPPORT ; ; This routine calls the SETUP_COMPACTION routine attempting to enable ; compaction on the device. If it succeeds in enabling compaction, it is ; assumed that the device supports compaction and the MT2$M_COMP_SUP bit is ; set in UCB$L_DEVDEPND2, otherwise it is cleared. If supported, compaction ; set back to whatever state it was previously in (MT2$M_COMP_ENA). ; ; INPUTS: ; ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUPUTS: ; ; R0 - Status ; R1,R2 - destroyed ;- CHECK_COMPACTION_SUPPORT: .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH= CLRB UCB$B_SAVED_COMP(R3) ; Assume compaction is off BBC #MT2$V_COMP_ENA, - ; Check current compaction state UCB$L_DEVDEPND2(R3), 5$; MOVB #1, UCB$B_SAVED_COMP(R3); Flag: compaction was enabled 5$: CMPB #2,- ; Only attempt compaction on SCSI-2+ UCB$B_SCSI_VERSION(R3) ; compliant devices BGTR 10$ ; Branch if scsi-1 DISABLE_ERRLOG ; Temporarily disable errorlogging BISL #UCB$M_COMPCHK_IN_PROG,-; Set compaction check in progress flag UCB$L_MK_FLAGS(R3) MOVL #1, R0 ; Attempt to turn on compaction BSBW SETUP_COMPACTION BICL #UCB$M_COMPCHK_IN_PROG,-; Clear compaction check in progress fl UCB$L_MK_FLAGS(R3) REENABLE_ERRLOG ; Reenable errorlogging BLBC R0,10$ ; LBC = not supported BISL #MT2$M_COMP_SUP,- ; Set DEVDPEND2 comp supported bit UCB$L_DEVDEPND2(R3) ; TSTB UCB$B_SAVED_COMP(R3) ; If compaction was already on, BNEQ 20$ ; leave it on CLRL R0 ; Compaction off flag BSBW SETUP_COMPACTION ; Turn it back off BRB 20$ 10$: BICL #MT2$M_COMP_SUP,- ; Clear DEVDPEND2 comp supported bit UCB$L_DEVDEPND2(R3) ; 20$: MOVL #1, R0 ; Always success RSB ; Return to caller .PAGE .SBTTL SETUP_COMPACTION - Use mode sense/select page 10 for compaction ;+ ; SETUP_COMPACTION ; ; This routine sends a MODE SENSE command which requests page 10. This is ; the Device Configuratin Page. At offset SCSI_MSEL$B_COMP is a byte ; which specifies if data compaction enabled or not. ; ; INPUTS: ; ; R0 - desired compaction state (0 = off, 1 = on) ; Values other than 0 or 1 are illegal. ; R3 - UCB address ; R4 - PDT address ; R5 - SCDRP address ; ; OUPUTS: ; ; R0 - Status ; R1,R2 - destroyed ;- ASSUME MT$K_DEFAULT EQ 0 SETUP_COMPACTION: ; ; issue a MODE_SENSE command to get the contents of page 10 ; .JSB_ENTRY INPUT=,OUTPUT=,SCRATCH=,- PRESERVE= ; Allocate a local copy of the mode page descriptors on the stack SUBL3 #DESCRIPTOR_SIZE,SP,R7 ; Size of descriptor array BICL #7,R7 ; Quadword align SUBL #DESCRIPTOR_SIZE+8,SP ; Account for desc + unalignment PUSHR #^M MOVC5 #0,.,#0,#DESCRIPTOR_SIZE,(R7) ; Initialize the desc area MOVC3 #DESCRIPTOR_SIZE,- ; Copy the descriptors DESCRIPTOR_BASE,(R7) POPR #^M MOVB R0, UCB$B_COMP_STATE(R3) ; Save requested compaction state MOVB UCB$B_COMP_STATE(R3),- ; Set desired compaction state (R7) PUSHL #^X10 ; Device configuration pg code PUSHAL DEV_CONFIG_PAGE_DESC(R7) ; Address of descriptors PUSHL R5 ; SCDRP Address CALLS #3,DO_MODE_PAGE ; Process the page BLBC R0,50$ ; Branch on error ;;; MOVL UCB$L_COMP_PAGE(R3),R1 ; Get address of compaction page info ;;; MOVZBL (R1)+,R0 ; Get length of info ;;; MOVB R0,5(R2) ; Put parameter list length in cmd ;;; MOVZBW R0,9(R2) ; Put BCNT in SCSI_CMD description ;;; SETUP_CMD ; Perform setup for SCSI command ;;; CLRL UCB$L_COMP_PAGE(R3) ; No longer valid pool address BICL #MT2$M_COMP_ENA,- ; Assume compaction is disabled UCB$L_DEVDEPND2(R3) TSTB UCB$B_COMP_STATE(R3) ; Check for state of comp_enabled flag BEQL 40$ ; 0 == compaction disabled BISL #MT2$M_COMP_ENA,- ; Indicate compaction is enabled UCB$L_DEVDEPND2(R3) ; 40$: ADDL #DESCRIPTOR_SIZE+8,SP ; Account for desc + unalignment RSB ; Return to caller 50$: MOVL #SS$_DRVERR,R0 BRW 40$ .PAGE .SBTTL + .SBTTL + TRACE ROUTINES .SBTTL + .SBTTL Trace buffer, symbols ;+ ; TRACE_BUFFER ; ; The driver uses a ring buffer to trace at the QIO, SCSI command, and SCSI ; cmd/status byte level. For each QIO issued, there can be zero or more SCSI ; commands sent, each of which can result in SCSI command, message, and status ; bytes. The trace buffer has the following format: ; ; +-----------------------+ <---- Start of trace buffer header ; | Size of trace buf | ; +-----------------------+ ; | Trace header size | ; +-----------------------+ ; | Total QIOs in buf | ; +-----------------------+ ; | Size of each QIO | ; +-----------------------+ ; | QIO header size | ; |-----------------------+ ; | # SCSI cmds/QIO | ; +-----------------------+ ; | Size of SCSI cmd | ; +-----------------------+ ; | Offset to SCSI sts | ; +-----------------------+ ; | Current QIO # | ; +-----------------------+ ; | | ; | RESERVED | ; | | ; +-----------------------+ <---- End of trace buffer header ; | QIO 0 | ; +-----------------------+ ; | QIO 1 | ; +-----------------------+ ; | . | ; | . | ; +-----------------------+ ; | QIO n-1 | ; +-----------------------+ ; ; For each QIO, the following information is logged: ; ; +-----------------------+ <---- Start of QIO header ; | QIO number | ; +-----------------------+ ; | Valid flag | ; +-----------------------+ ; | SCSI command cnt | ; +-----------------------+ ; | SCSI bus ID | ; +-----------------------+ ; | Function code | ; +-----------------------+ ; | Media (LBN) | ; +-----------------------+ ; | Byte count | ; +-----------------------+ ; | Byte offset | ; +-----------------------+ ; | QIO status | ; +-----------------------+ ; | Sequence number | ; +-----------------------+ ; | | ; | RESERVED | ; | | ; +-----------------------+ <---- End of QIO header ; | SCSI CMD 0 | ; +-----------------------+ ; | SCSI CMD 1 | ; +-----------------------+ ; | . | ; | . | ; +-----------------------+ ; | SCSI CMD n-1 | ; +-----------------------+ ; ; Finally, for each SCSI command, the following information is logged: ; ; +-----------------------+ ; | CMD byte cnt | ; +-----------------------+ ; | SCSI CMD bytes | ; +-----------------------+ ; | SCSI status byte | ; +-----------------------+ ; ; Note that CMD byte count is kept to allow the tracing routines to know where ; to put the next CMD byte and to allow the user to know how much data to ; interpret. Also note that, in order to make it easier to interpret, the data ; is not packed in as well as it could be. ;- $DEFINI TRACE_BUFFER_HEADER $DEF TR$L_SIZE .BLKL 1 $DEF TR$L_HEADER_SIZE .BLKL 1 $DEF TR$L_TOTAL_QIOS .BLKL 1 $DEF TR$L_CURRENT_QIO .BLKL 1 $DEF TR$L_QIO_SEQNUM .BLKL 1 $DEF TR$L_QIO_SIZE .BLKL 1 $DEF TR$L_QIO_HEADER_SIZE .BLKL 1 $DEF TR$L_SCSI_CMDS_PER_QIO .BLKL 1 $DEF TR$L_SCSI_CMD_SIZE .BLKL 1 $DEF TR$L_SCSI_MSG_OFFSET .BLKL 1 $DEF TR$L_SCSI_STATUS_OFFSET .BLKL 1 $DEF TR$C_HEADER_SIZE $DEFEND TRACE_BUFFER_HEADER $DEFINI TRACE_BUFFER_QIO_HEADER $DEF TR$L_QIO_NUMBER .BLKL 1 $DEF TR$L_VALID_FLAG .BLKL 1 $DEF TR$L_SCSI_CMD_CNT .BLKL 1 $DEF TR$L_DEVICE_NAME .BLKL 1 $DEF TR$L_SCSI_UNIT_NUMBER .BLKL 1 $DEF TR$L_QIO_FUNC .BLKL 1 $DEF TR$L_QIO_MEDIA .BLKL 1 $DEF TR$L_QIO_BCNT .BLKL 1 $DEF TR$L_QIO_BOFF .BLKL 1 $DEF TR$L_QIO_STATUS .BLKL 1 $DEF TR$L_SEQNUM .BLKL 1 $DEF TR$L_RECORD .BLKL 1 $DEF TR$L_DEVDEPEND .BLKL 1 $DEF TR$C_QIO_HEADER_SIZE $DEFEND TRACE_BUFFER_QIO_HEADER TR$TOTAL_QIOS = 200 TR$SCSI_CMDS_PER_QIO = 0 TR$CMD_BYTES = 12 TR$MSG_BYTES = 12 TR$STATUS_BYTES = 1 TR$SCSI_MSG_OFFSET = TR$CMD_BYTES+4 TR$SCSI_STATUS_OFFSET = TR$CMD_BYTES+4 + TR$MSG_BYTES+4 TR$SCSI_CMD_SIZE = < + 15> & ^C15 TR$QIO_SIZE = <> + 15> & ^C15 TR$TRACE_BUFFER_SIZE = TR$C_HEADER_SIZE + DRIVER_DATA TR$TRACE_BUFFER_ADDR: .LONG 0 .PAGE .SBTTL SETUP_TRACE - Allocate and set up trace buffer ;+ ; SETUP_TRACE ; ; This is a fork routine queued by unit init to allocate a trace buffer, which ; is used to trace QIOs through the driver. The auxstruc field in the CRB is ; filled in with the address of a cell which contains the address of the trace ; buffer. Since the driver can have more than one unit, only the first ; call to this routine actually performs the allocation. Since pool allocation ; can stall this thread, the TR$TRACE_BUFFER_ADDR cell is given a value of ; 1 (positive integer) to indicate that poll allocation is on progress. This ; prevents a second thread from allocating another buffer. ; ; INPUTS: ; ; R5 - CRB address ; ; OUTPUTS: ; ; R0-R3 - Destroyed ; All other registers preserved ; ; CRB$L_AUXSTRUC - Address of cell containing trace buffer address ;- DRIVER_CODE SETUP_TRACE: FORK_ROUTINE ; INPUT=,SCRATCH= .IF DEFINED DEBUG TSTL TR$TRACE_BUFFER_ADDR ; Trace buffer already set up? BNEQ 10$ ; Branch if so INCL TR$TRACE_BUFFER_ADDR ; Trace buffer setup in progress MOVL #TR$TRACE_BUFFER_SIZE,R1; Get size of trace buffer JSB G^EXE$ALONONPAGED ; Allocate pool BLBS R0,5$ ; Branch if success CLRL TR$TRACE_BUFFER_ADDR ; Trace buffer not allocated BRB 20$ ; Use common exit 5$: PUSHL R2 ; Save reg MOVC5 #0,(SP),#0,R1,(R2) ; Initialize the packet POPL R2 ; Restore reg MOVL #TR$TRACE_BUFFER_SIZE,- ; Save trace buffer size TR$L_SIZE(R2) ; MOVL #TR$C_HEADER_SIZE,- ; Save header size TR$L_HEADER_SIZE(R2) ; MOVL #TR$TOTAL_QIOS,- ; Save total number of QIOs in TR$L_TOTAL_QIOS(R2) ; buffer MOVL #TR$QIO_SIZE,- ; Save size of QIO TR$L_QIO_SIZE(R2) ; MOVL #TR$C_QIO_HEADER_SIZE,- ; Save size of QIO header TR$L_QIO_HEADER_SIZE(R2); MOVL R2,TR$TRACE_BUFFER_ADDR ; Save trace buffer address 10$: .ENDC 20$: MOVAL TR$TRACE_BUFFER_ADDR,- ; Save address of cell pointing to CRB$L_AUXSTRUC(R5) ; trace buffer in CRB RSB .PAGE .IF DEFINED DEBUG .SBTTL TRACE_QIO - Trace QIO requests ;+ ; TRACE_QIO ; ; This routine logs information from the current QIO packet including the ; function code, MEDIA, BCNT, and BOFF fields. ; ; INPUTS: ; ; R3 - IRP address or 0 if UNIT INIT ; R5 - UCB address ; ; OUTPUTS: ; ; All registers preserved ;- TRACE_QIO: .JSB_ENTRY INPUT=,PRESERVE= MOVL TR$TRACE_BUFFER_ADDR,R0 ; Get trace buffer address BGEQ 30$ ; Branch if none ADDL3 #1,- ; Bump QIO number TR$L_CURRENT_QIO(R0),R1 ; CMPL R1,#TR$TOTAL_QIOS ; Time to wrap QIO number? BLSS 10$ ; Branch if not CLRL R1 ; Wrap QIO number 10$: MOVL R1,TR$L_CURRENT_QIO(R0) ; Save QIO number MULL3 #TR$QIO_SIZE,R1,R2 ; Get offset of this QIO in trace buffer ADDL R0,R2 ; Address to place info for this QIO ADDL #TR$C_HEADER_SIZE,R2 ; Account for trace buffer header PUSHR #^M ; Save regs MOVC5 #0,(SP),#0,#TR$QIO_SIZE,- ; Clear entire buffer used to trace (R2) ; this QIO POPR #^M ; Restore regs ADDL3 #TR$C_QIO_HEADER_SIZE,- ; Get address of place to store R2,R1 ; first SCSI command MOVL TR$L_CURRENT_QIO(R0),- ; Save QIO number (R2)+ ; MOVL #1,(R2)+ ; Set valid flag CLRL (R2)+ ; Clear SCSI command count MOVL UCB$L_DDB(R5),R1 ; Get DDB address MOVL DDB$T_NAME_STR(R1),(R2)+; Save SCSI device name MOVZWL UCB$W_UNIT(R5),(R2)+ ; Trace SCSI bus ID TSTL R3 ; IRP address of 0 (unit init)? BEQL 15$ ; Branch if so MOVL IRP$L_FUNC(R3),(R2)+ ; Trace QIO function code MOVL IRP$L_MEDIA(R3),(R2)+ ; Trace media number (LBN) MOVL IRP$L_BCNT(R3),(R2)+ ; Trace byte count MOVL IRP$L_BOFF(R3),(R2)+ ; Trace byte offset BRB 20$ ; Skip unit init path 15$: MCOML #0,(R2)+ ; Special function code for UNIT INIT ADDL #12,R2 ; Skip MEDIA, BCNT, BOFF fields 20$: MOVL R2,UCB$L_TR_QIO_STS(R5) ; Save address to put QIO status MCOML #0,(R2)+ ; Initialize QIO status MOVL TR$L_QIO_SEQNUM(R0),- ; Save QIO sequence number (R2)+ ; INCL TR$L_QIO_SEQNUM(R0) ; Bump QIO sequence number 30$: RSB ; Return to caller .ENDC ; .IF DEFINED DEBUG .PAGE .SBTTL TRACE_QIO_STAT - Save final status from QIO in trace buffer ;+ ; TRACE_QIO_STAT ; ; This routine saves the final QIO status in the trace buffer. ; ; INPUTS: ; R5 - UCB address ; ; OUTPUTS: ; R2 - Destroyed ; ;- TRACE_QIO_STAT: .JSB_ENTRY INPUT=,SCRATCH= MOVL UCB$L_TR_QIO_STS(R5),R2 ; Get address to put status BEQL 10$ ; Branch if uninitialized MOVL R0,(R2) ; Save status in trace buffer ASSUME TR$L_QIO_STATUS+8 EQ TR$L_RECORD ASSUME TR$L_QIO_STATUS+12 EQ TR$L_DEVDEPEND MOVL UCB$L_RECORD(R5),8(R2) ; Save current record number MOVL UCB$L_DEVDEPEND(R5),- ; Save DEVDEPND info 12(R2) ; 10$: RSB MK_END: ; Last location in driver .END