* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Van Jacobson of Lawrence Berkeley Laboratory and the Systems
* Programming Group of the University of Utah Computer Science Department.
* %sccs.include.redist.c%
* from: Utah $Hdr: scsi.c 1.3 90/01/27$
* @(#)scsi.c 7.3 (Berkeley) %G%
* SCSI bus driver for standalone programs.
#include "../dev/device.h"
#include "../dev/scsireg.h"
struct scsi_softc scsi_softc
[NSCSI
];
#define scsiunit(x) ((x) >> 3)
#define scsislave(x) ((x) & 7)
int scsi_data_wait
= 300000;
extern struct hp_hw sc_table
[];
register struct hp_hw
*hw
;
register struct scsi_softc
*hs
;
for (hw
= sc_table
; i
< NSCSI
&& hw
< &sc_table
[MAX_CTLR
]; hw
++) {
hs
->sc_addr
= hw
->hw_addr
;
printf("scsi%d at sc%d\n", i
, hw
->hw_sc
);
* Adjust devtype on first call. This routine assumes that
* adaptor is in the high byte of devtype.
if (first
&& ((devtype
>> 24) & 0xff) == hw
->hw_sc
) {
devtype
= (devtype
& 0x00ffffff) | (i
<< 24);
if (unit
>= NSCSI
|| scsi_softc
[unit
].sc_alive
== 0)
volatile register struct scsidevice
*hd
;
register struct scsi_softc
*hs
;
hd
= (struct scsidevice
*)hs
->sc_addr
;
* Disable interrupts then reset the FUJI chip.
hd
->scsi_sctl
= SCTL_DISABLE
| SCTL_CTRLRST
;
* Configure the FUJI chip with its SCSI address, all
* interrupts enabled & appropriate parity.
i
= (~hd
->scsi_hconf
) & 0x7;
hs
->sc_scsi_addr
= 1 << i
;
if (hd
->scsi_hconf
& HCONF_PARITY
)
hd
->scsi_sctl
= SCTL_DISABLE
| SCTL_ABRT_ENAB
|
SCTL_SEL_ENAB
| SCTL_RESEL_ENAB
|
SCTL_INTR_ENAB
| SCTL_PARITY_ENAB
;
hd
->scsi_sctl
= SCTL_DISABLE
| SCTL_ABRT_ENAB
|
SCTL_SEL_ENAB
| SCTL_RESEL_ENAB
|
hd
->scsi_sctl
&=~ SCTL_DISABLE
;
register struct scsi_softc
*hs
;
volatile register struct scsidevice
*hd
;
printf("scsi error: scsiabort\n");
issue_select(hd
, target
, our_addr
)
volatile register struct scsidevice
*hd
;
if (hd
->scsi_ssts
& (SSTS_INITIATOR
|SSTS_TARGET
|SSTS_BUSY
))
if (hd
->scsi_ints
& INTS_DISCON
)
hd
->scsi_ints
= INTS_DISCON
;
hd
->scsi_temp
= (1 << target
) | our_addr
;
/* select timeout is hardcoded to 2ms */
hd
->scsi_scmd
= SCMD_SELECT
;
volatile register struct scsidevice
*hd
;
while ((ints
= hd
->scsi_ints
) == 0)
return (!(hd
->scsi_ssts
& SSTS_INITIATOR
));
ixfer_start(hd
, len
, phase
, wait
)
volatile register struct scsidevice
*hd
;
hd
->scsi_tch
= len
>> 16;
hd
->scsi_tmod
= 0; /*XXX*/
hd
->scsi_scmd
= SCMD_XFR
| SCMD_PROG_XFR
;
/* wait for xfer to start or svc_req interrupt */
while ((hd
->scsi_ssts
& SSTS_BUSY
) == 0) {
if (hd
->scsi_ints
|| --wait
< 0)
volatile register struct scsidevice
*hd
;
register int wait
= scsi_data_wait
;
while (hd
->scsi_ssts
& SSTS_DREG_FULL
) {
if (hd
->scsi_ints
|| --wait
< 0)
volatile register struct scsidevice
*hd
;
register int wait
= scsi_data_wait
;
while (hd
->scsi_ssts
& SSTS_DREG_EMPTY
) {
if (hd
->scsi_ints
|| --wait
< 0) {
while (! (hd
->scsi_ssts
& SSTS_DREG_EMPTY
)) {
scsiicmd(hs
, target
, cbuf
, clen
, buf
, len
, xferphase
)
volatile register struct scsidevice
*hd
=
(struct scsidevice
*)hs
->sc_addr
;
/* select the SCSI bus (it's an error if bus isn't free) */
if (issue_select(hd
, target
, hs
->sc_scsi_addr
))
* Wait for a phase change (or error) then let the device
* sequence us through the various SCSI phases.
if (ixfer_start(hd
, clen
, phase
, wait
))
if (ixfer_out(hd
, clen
, cbuf
))
if (ixfer_start(hd
, len
, phase
, wait
) ||
!(hd
->scsi_ssts
& SSTS_DREG_EMPTY
))
if (ixfer_start(hd
, len
, phase
, wait
))
if (ixfer_out(hd
, len
, buf
))
if (ixfer_start(hd
, sizeof(hs
->sc_stat
), phase
, wait
) ||
!(hd
->scsi_ssts
& SSTS_DREG_EMPTY
))
ixfer_in(hd
, sizeof(hs
->sc_stat
), &hs
->sc_stat
);
if (ixfer_start(hd
, sizeof(hs
->sc_msg
), phase
, wait
) ||
!(hd
->scsi_ssts
& SSTS_DREG_EMPTY
)) {
ixfer_in(hd
, sizeof(hs
->sc_msg
), &hs
->sc_msg
);
hd
->scsi_scmd
= SCMD_RST_ACK
;
printf("unexpected scsi phase %d\n", phase
);
/* wait for last command to complete */
while ((ints
= hd
->scsi_ints
) == 0) {
phase
= hd
->scsi_psns
& PHASE
;
else if (ints
& INTS_DISCON
)
else if ((ints
& INTS_CMD_DONE
) == 0) {
int ctlr
= scsiunit(unit
);
int slave
= scsislave(unit
);
register struct scsi_softc
*hs
= &scsi_softc
[ctlr
];
static struct scsi_cdb6 cdb
= { CMD_TEST_UNIT_READY
};
if (scsiicmd(hs
, slave
, &cdb
, sizeof(cdb
), (u_char
*)0, 0,
return (hs
->sc_stat
== 0);
scsi_request_sense(unit
, buf
, len
)
int ctlr
= scsiunit(unit
);
int slave
= scsislave(unit
);
register struct scsi_softc
*hs
= &scsi_softc
[ctlr
];
static struct scsi_cdb6 cdb
= { CMD_REQUEST_SENSE
};
return (scsiicmd(hs
, slave
, &cdb
, sizeof(cdb
), buf
, len
, DATA_IN_PHASE
));
scsi_read_capacity(unit
, buf
, len
)
int ctlr
= scsiunit(unit
);
int slave
= scsislave(unit
);
register struct scsi_softc
*hs
= &scsi_softc
[ctlr
];
static struct scsi_cdb10 cdb
= { CMD_READ_CAPACITY
};
return (scsiicmd(hs
, slave
, &cdb
, sizeof(cdb
), buf
, len
, DATA_IN_PHASE
));
scsi_tt_read(unit
, buf
, len
, blk
, nblk
)
int ctlr
= scsiunit(unit
);
int slave
= scsislave(unit
);
register struct scsi_softc
*hs
= &scsi_softc
[ctlr
];
bzero(&cdb
, sizeof(cdb
));
cdb
.lenh
= nblk
>> (8 + DEV_BSHIFT
);
cdb
.lenl
= nblk
>> DEV_BSHIFT
;
stat
= scsiicmd(hs
, slave
, &cdb
, sizeof(cdb
), buf
, len
, DATA_IN_PHASE
);
scsi_tt_write(unit
, buf
, len
, blk
, nblk
)
int ctlr
= scsiunit(unit
);
int slave
= scsislave(unit
);
register struct scsi_softc
*hs
= &scsi_softc
[ctlr
];
bzero(&cdb
, sizeof(cdb
));
cdb
.lenh
= nblk
>> (8 + DEV_BSHIFT
);
cdb
.lenl
= nblk
>> DEV_BSHIFT
;
stat
= scsiicmd(hs
, slave
, &cdb
, sizeof(cdb
), buf
, len
, DATA_OUT_PHASE
);