* Copyright (c) 1992 OMRON Corporation.
* Copyright (c) 1992 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* %sccs.include.redist.c%
* @(#)st.c 7.4 (Berkeley) %G%
* st.c -- TEAC MT-2ST/N60 SCSI TAPE UNIT Device Driver
* remaked by A.Fujita, MAR-22-1992
* SCSI CCS (Command Command Set) disk driver.
#include <luna68k/dev/device.h>
#include <luna68k/dev/scsireg.h>
#include <luna68k/dev/scsivar.h>
extern int scsi_test_unit_rdy();
extern int scsi_request_sense();
extern int scsi_immed_command();
extern char *scsi_status();
int stinit(), ststrategy(), ststart(), stintr();
struct driver stdriver
= {
stinit
, "st", ststart
, (int (*)()) 0, stintr
, (int (*)()) 0
short sc_type
; /* drive type */
short sc_punit
; /* physical unit (scsi lun) */
struct scsi_fmt_cdb st_read_cmd
= { 6, CMD_READ
};
struct scsi_fmt_cdb st_write_cmd
= { 6, CMD_WRITE
};
#define stunit(x) (minor(x) & 3)
#define stpunit(x) ((x) & 7)
#define STDEV_NOREWIND 0x04
#define STRETRY 2 /* IO retry count */
struct st_iostat st_iostat
[NST
];
register struct hp_device
*hd
;
register struct st_softc
*sc
= &st_softc
[hd
->hp_unit
];
sc
->sc_punit
= stpunit(hd
->hp_flags
);
sc
->sc_type
= stident(sc
, hd
);
sc
->sc_dq
.dq_ctlr
= hd
->hp_ctlr
;
sc
->sc_dq
.dq_unit
= hd
->hp_unit
;
sc
->sc_dq
.dq_slave
= hd
->hp_slave
;
sc
->sc_dq
.dq_driver
= &stdriver
;
sc
->sc_flags
= STF_ALIVE
;
static struct scsi_inquiry inqbuf
;
static struct scsi_fmt_cdb inq
= {
CMD_INQUIRY
, 0, 0, 0, sizeof(inqbuf
), 0
register int ctlr
, slave
;
* See if unit exists and is a disk then read block size & nblocks.
while ((stat
= scsi_immed_command(ctlr
, slave
, unit
,
&inq
, (u_char
*)&inqbuf
, sizeof(inqbuf
))) != 0) {
if (stat
< 0 || --tries
< 0)
default: /* not a disk */
printf("stident: inqbuf.type = %d\n", inqbuf
.type
);
bcopy((caddr_t
)&inqbuf
.vendor_id
, (caddr_t
)idstr
, 28);
for (i
= 27; i
> 23; --i
)
printf("st%d: %s %s rev %s\n", hd
->hp_unit
, idstr
, &idstr
[8],
stopen(dev
, flag
, type
, p
)
register int unit
= stunit(dev
);
register struct st_softc
*sc
= &st_softc
[unit
];
register struct scsi_xsense
*sp
= (struct scsi_xsense
*) xsense_buff
;
int ctlr
= sc
->sc_dq
.dq_ctlr
;
int slave
= sc
->sc_dq
.dq_slave
;
if (unit
>= NST
|| (sc
->sc_flags
& STF_ALIVE
) == 0)
if (sc
->sc_flags
& STF_OPEN
)
while ((stat
= scsi_test_unit_rdy(ctlr
, slave
, 0)) != 0) {
scsi_request_sense(ctlr
, slave
, 0, sp
, 8);
if (stat
!= STS_CHECKCOND
) {
printf("st%d: stopen: %s\n", scsi_status(stat
));
printf("st%d: stopen: %s\n", sense_key(sp
->key
));
sc
->sc_ctty
= tprintf_open(p
);
sc
->sc_flags
|= STF_OPEN
;
sc
->sc_flags
|= STF_WMODE
;
sc
->sc_flags
&= ~STF_MOVED
;
register int unit
= stunit(dev
);
register struct st_softc
*sc
= &st_softc
[unit
];
register struct scsi_xsense
*sp
= (struct scsi_xsense
*) xsense_buff
;
int ctlr
= sc
->sc_hd
->hp_ctlr
;
int slave
= sc
->sc_hd
->hp_slave
;
if ((sc
->sc_flags
& (STF_WMODE
|STF_WRTTN
)) == (STF_WMODE
|STF_WRTTN
)) {
if ((minor(dev
) & STDEV_NOREWIND
) == 0) {
sc
->sc_flags
&= ~(STF_OPEN
|STF_WMODE
|STF_WRTTN
);
tprintf_close(sc
->sc_ctty
);
register int unit
= stunit(bp
->b_dev
);
register struct buf
*dp
= &sttab
[unit
];
dp
->b_actl
->av_forw
= bp
;
register struct st_softc
*sc
= &st_softc
[unit
];
register struct hp_device
*hp
= sc
->sc_hd
;
register struct scsi_queue
*dq
= &sc
->sc_dq
;
register struct buf
*bp
= sttab
[unit
].b_actf
;
register struct scsi_fmt_cdb
*cmd
;
cmd
= bp
->b_flags
& B_READ
? &st_read_cmd
: &st_write_cmd
;
cmd
->cdb
[1] = 1; /* unknown setup */
if (bp
->b_flags
& B_READ
)
sc
->sc_flags
&= ~STF_WRTTN
;
sc
->sc_flags
|= STF_WRTTN
;
nblks
= bp
->b_bcount
>> DEV_BSHIFT
;
if (bp
->b_bcount
% DEV_BSIZE
) {
"st%d: I/O not block aligned %d/%ld\n",
unit
, DEV_BSIZE
, bp
->b_bcount
);
sttab
[unit
].b_errcnt
= 0;
sttab
[unit
].b_actf
= bp
->b_actf
;
if (sttab
[unit
].b_actf
) {
sttab
[unit
].b_active
= 0;
*(u_char
*)(&cmd
->cdb
[2]) = (u_char
) (nblks
>> 16);
*(u_char
*)(&cmd
->cdb
[3]) = (u_char
) (nblks
>> 8);
*(u_char
*)(&cmd
->cdb
[4]) = (u_char
) nblks
;
cmd
->cdb
[5] = 0; /* unknown setup */
sc
->sc_flags
|= STF_MOVED
;
dq
->dq_flags
= 0; /* No Disconnect */
register struct st_softc
*sc
= &st_softc
[unit
];
register struct hp_device
*hp
= sc
->sc_hd
;
return("Hardware Error");
return("Illegal Request");
return("Unit Attention");
return("Aborted Command");
return("Volume Overflow");
register struct st_softc
*sc
= &st_softc
[unit
];
register struct scsi_xsense
*xp
= (struct scsi_xsense
*) xsense_buff
;
register struct scsi_queue
*dq
= &sc
->sc_dq
;
register struct buf
*bp
= dq
->dq_bp
;
int slave
= dq
->dq_slave
;
if (bp
->b_flags
& B_READ
) {
st_iostat
[unit
].imin
= min(dq
->dq_imin
, st_iostat
[unit
].imin
);
if (dq
->dq_imax
> st_iostat
[unit
].imax
) {
st_iostat
[unit
].imax
= dq
->dq_imax
;
printf("stintr: st%d INPUT MAX = %d, MIN = %d\n",
unit
, st_iostat
[unit
].imax
, st_iostat
[unit
].imin
);
st_iostat
[unit
].omin
= min(dq
->dq_omin
, st_iostat
[unit
].omin
);
if (dq
->dq_omax
> st_iostat
[unit
].omax
) {
st_iostat
[unit
].omax
= dq
->dq_omax
;
printf("stintr: st%d OUTPUT MAX = %d, MIN = %d\n",
unit
, st_iostat
[unit
].omax
, st_iostat
[unit
].omin
);
/* scsi command completed ok */
scsi_request_sense(ctlr
, slave
, 0, xp
, 8);
printf("stintr: xsense_buff[0] = 0x%s\n", hexstr(xsense_buff
[0], 2));
printf("stintr: xsense_buff[2] = 0x%s\n", hexstr(xsense_buff
[2], 2));
printf("stintr: Sense Key = [%s]\n", sense_key(xp
->key
));
bp
->b_resid
= (u_long
)((xp
->info1
<< 24) |
bp
->b_resid
<<= DEV_BSHIFT
;
if (xp
->filemark
) { /* End of File */
tprintf(sc
->sc_ctty
, "st%d: End of File\n", unit
);
tprintf(sc
->sc_ctty
, "st%d: %s\n", unit
, sense_key(xp
->key
));
if (xp
->eom
) { /* End of TAPE */
tprintf(sc
->sc_ctty
, "st%d: End of Tape\n", unit
);
tprintf(sc
->sc_ctty
, "st%d: unknown scsi error\n", unit
);
printf("st%d: stintr unknown stat 0x%x\n", unit
, stat
);
sttab
[unit
].b_errcnt
= 0;
sttab
[unit
].b_actf
= bp
->b_actf
;
if (sttab
[unit
].b_actf
) {
sttab
[unit
].b_active
= 0;
return(physio(ststrategy
, &stbuf
[unit
], dev
, B_READ
, minphys
, uio
));
return(physio(ststrategy
, &stbuf
[unit
], dev
, B_WRITE
, minphys
, uio
));
stioctl(dev
, cmd
, data
, flag
, p
)
struct scsi_fmt_cdb st_cmd
;
register int unit
= stunit(dev
);
register struct st_softc
*sc
= &st_softc
[unit
];
register struct scsi_fmt_cdb
*cdb
= &st_cmd
;
register struct scsi_xsense
*sp
= (struct scsi_xsense
*) xsense_buff
;
ctlr
= sc
->sc_hd
->hp_ctlr
;
slave
= sc
->sc_hd
->hp_slave
;
cdb
->cdb
[0] = CMD_REWIND
;
cdb
->cdb
[1] = 1; /* command finished soon */
cdb
->cdb
[5] = 0; /* unknown setup */
stat
= scsi_immed_command(ctlr
, slave
, 0, cdb
, (char *) 0, 0);
printf("st: rewind error\n");
scsi_request_sense(ctlr
, slave
, 0, sp
, 8);
printf("st: status = 0x%x, sens key = 0x%x\n", stat
, sp
->key
);
register int unit
= stunit(dev
);
register struct st_softc
*sc
= &st_softc
[unit
];
register struct scsi_fmt_cdb
*cdb
= &st_cmd
;
ctlr
= sc
->sc_hd
->hp_ctlr
;
slave
= sc
->sc_hd
->hp_slave
;
cdb
->cdb
[0] = CMD_WRITE_FILEMARK
;
cdb
->cdb
[5] = 0; /* unknown setup */
stat
= scsi_immed_command(ctlr
, slave
, 0, cdb
, (char *) 0, 0);
printf("st: write EOF error\n");