/* @(#)tmscp.c 7.5 (Berkeley) %G% */
/****************************************************************
* Licensed from Digital Equipment Corporation *
* Digital Equipment Corporation *
* Maynard, Massachusetts *
* The Information in this software is subject to change *
* without notice and should not be construed as a commitment *
* by Digital Equipment Corporation. Digital makes no *
* representations about the suitability of this software for *
* any purpose. It is supplied "As Is" without expressed or *
* If the Regents of the University of California or its *
* licensees modify the software in a manner creating *
* diriviative copyright rights, appropriate copyright *
* legends may be placed on the drivative work in addition *
* to that set forth above. *
***************************************************************/
* tmscp.c - TMSCP (TK50/TU81) standalone driver
static char *sccsid
= "@(#)tmscp.c 1.5 (ULTRIX) 4/18/86";
/* ------------------------------------------------------------------------
* Modification History: /sys/stand/tmscp.c
* Don't ask for an interrupt when commands are issued and
* check ownership bit in the response descriptor to detect when a
* command is complete. Necessary due to the TU81's failure to set
* the response interrupt field in the communications area.
* ------------------------------------------------------------------------
* Parameters for the communications area
* (Only 1 cmd & 1 rsp packet)
#include "../vaxuba/tmscpreg.h"
#include "../vaxuba/ubareg.h"
#include "../vax/tmscp.h"
#define MAXCTLR 1 /* all addresses must be specified */
u_short tmscpstd
[MAXCTLR
] = { 0174500 };
struct tmscpdevice
*tmscpaddr
= 0;
struct tmscp
*tmscp_ubaddr
; /* Unibus address of tmscp structure */
int tmscp_offline
= 1; /* Flag to prevent multiple STCON */
int tms_offline
[4] = {1,1,1,1}; /* Flag to prevent multiple ONLIN */
* Open a tmscp device. Initialize the controller and set the unit online.
register struct mscp
*mp
;
if ((u_int
)io
->i_ctlr
>= MAXCTLR
)
* Have the tmscp controller characteristics already been set up
tmscpaddr
= (struct tmscpdevice
*)ubamem(io
->i_adapt
, tmscpstd
[0]);
ctmscpbuf
.i_ma
= (caddr_t
)&tmscp
;
ctmscpbuf
.i_cc
= sizeof(tmscp
);
tmscp_ubaddr
= (struct tmscp
*)ubasetup(&ctmscpbuf
, 2);
* Initialize the tmscp device and wait for the 4 steps
while ((tmscpaddr
->tmscpsa
& TMSCP_STEP1
) == 0);
tmscpaddr
->tmscpsa
=TMSCP_ERR
|(NCMDL2
<<11)|(NRSPL2
<<8);
while ((tmscpaddr
->tmscpsa
& TMSCP_STEP2
) == 0);
# define STEP1MASK 0174377
# define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
if ((tmscpaddr
->tmscpsa
&STEP1MASK
) != STEP1GOOD
)
printf("tmscpopen: step 1 not successful sa=%o\n",tmscpaddr
->tmscpsa
&0xffff);
tmscpaddr
->tmscpsa
= (short)&tmscp_ubaddr
->tmscp_ca
.ca_ringbase
;
while ((tmscpaddr
->tmscpsa
& TMSCP_STEP3
) == 0);
# define STEP2MASK 0174377
# define STEP2GOOD (TMSCP_STEP3)
if ((tmscpaddr
->tmscpsa
&STEP2MASK
) != STEP2GOOD
)
printf("tmscpopen: step 2 not successful sa=%o\n",tmscpaddr
->tmscpsa
&0xffff);
tmscpaddr
->tmscpsa
= (short)(((int)&tmscp_ubaddr
->tmscp_ca
.ca_ringbase
) >> 16);
while ((tmscpaddr
->tmscpsa
& TMSCP_STEP4
) == 0);
# define STEP3MASK 0174000
# define STEP3GOOD TMSCP_STEP4
if ((tmscpaddr
->tmscpsa
&STEP3MASK
) != STEP3GOOD
)
printf("tmscpopen: step 3 not successful sa=%o\n",tmscpaddr
->tmscpsa
&0xffff);
tmscpaddr
->tmscpsa
= TMSCP_GO
;
tmscp
.tmscp_ca
.ca_cmddsc
[0] = (long)&tmscp_ubaddr
->tmscp_cmd
.mscp_cmdref
;
tmscp
.tmscp_cmd
.mscp_dscptr
= tmscp
.tmscp_ca
.ca_cmddsc
;
tmscp
.tmscp_cmd
.mscp_header
.tmscp_vcid
= 1; /* for tape */
tmscp
.tmscp_ca
.ca_rspdsc
[0] = (long)&tmscp_ubaddr
->tmscp_rsp
.mscp_cmdref
;
tmscp
.tmscp_rsp
.mscp_dscptr
= tmscp
.tmscp_ca
.ca_rspdsc
;
tmscp
.tmscp_cmd
.mscp_cntflgs
= 0;
if (tmscpcmd(M_OP_STCON
, 0) == 0) {
printf("tms: open error, STCON\n");
tmscp
.tmscp_cmd
.mscp_unit
= io
->i_unit
&03;
* Has this unit been issued an ONLIN?
if (tms_offline
[tmscp
.tmscp_cmd
.mscp_unit
]) {
if ((mp
= tmscpcmd(M_OP_ONLIN
, 0)) == 0) {
_stop("tms: open error, ONLIN\n");
tms_offline
[tmscp
.tmscp_cmd
.mscp_unit
] = 0;
* This makes no sense, but I could be wrong... KB
* if ((u_int)io->i_part > 3)
* Skip forward the appropriate number of files on the tape.
tmscp
.tmscp_cmd
.mscp_tmkcnt
= io
->i_part
;
(void)tmscpcmd(M_OP_REPOS
, 0);
tmscp
.tmscp_cmd
.mscp_tmkcnt
= 0;
* Close the device (rewind it to BOT)
(void)tmscpcmd(M_OP_REPOS
, M_MD_REWND
);
* Set up tmscp command packet. Cause the controller to poll to pick up
int op
, mod
; /* opcode and modifier (usu 0) */
struct mscp
*mp
; /* ptr to cmd packet */
int i
; /* read into to init polling */
tmscp
.tmscp_cmd
.mscp_opcode
= op
;
tmscp
.tmscp_cmd
.mscp_modifier
= mod
;
tmscp
.tmscp_cmd
.mscp_header
.tmscp_msglen
= mscp_msglen
;
tmscp
.tmscp_ca
.ca_cmddsc
[0] |= TMSCP_OWN
; /* | TMSCP_INT */
tmscp
.tmscp_rsp
.mscp_header
.tmscp_msglen
= mscp_msglen
;
tmscp
.tmscp_ca
.ca_rspdsc
[0] |= TMSCP_OWN
; /* | TMSCP_INT */
if (tmscpaddr
->tmscpsa
& TMSCP_ERR
) {
printf("tmscpcmd: Fatal error sa=%o\n", tmscpaddr
->tmscpsa
& 0xffff);
if (tmscp
.tmscp_ca
.ca_cmdint
)
tmscp
.tmscp_ca
.ca_cmdint
= 0;
* This is to handle the case of devices not setting the
* interrupt field in the communications area. Some
* devices (early TU81's) only clear the ownership field
* in the Response Descriptor.
* if (tmscp.tmscp_ca.ca_rspint)
if (!(tmscp
.tmscp_ca
.ca_rspdsc
[0] & (TMSCP_OWN
)))
tmscp
.tmscp_ca
.ca_rspint
= 0;
if (mp
->mscp_opcode
!= (op
|M_OP_END
) ||
(mp
->mscp_status
&M_ST_MASK
) != M_ST_SUCC
) {
* Detect hitting tape mark. This signifies the end of the
* tape mini-root file. We don't want to return an error
* condition to the strategy routine.
if ((mp
->mscp_status
& M_ST_MASK
) != M_ST_TAPEM
)
* Set up to do reads and writes; call tmscpcmd to issue the cmd.
register struct mscp
*mp
;
ubinfo
= ubasetup(io
, 1);
mp
->mscp_unit
= io
->i_unit
&03;
mp
->mscp_bytecnt
= io
->i_cc
;
mp
->mscp_buffer
= (ubinfo
& 0x3fffff) | (((ubinfo
>>28)&0xf)<<24);
if ((mp
= tmscpcmd(func
== READ
? M_OP_READ
: M_OP_WRITE
, 0)) == 0) {
printf("tms: I/O error\n");
* Detect hitting tape mark so we do it gracefully and return a
* character count of 0 to signify end of copy. Rewind the tape
if ((mp
->mscp_status
& M_ST_MASK
) == M_ST_TAPEM
)