
/*
 *  SCSI.C
 */

#include "defs.h"

Prototype int  SCSIOpen(Chan *);
Prototype void SCSIClose(Chan *);
Prototype int  DoSCSI(Chan *, char *, char *, long, ubyte, long *);
Prototype void SendSCSI(Chan *, char *, char *, long, ubyte);
Prototype int  WaitSCSI(Chan *, long *);

static __aligned ubyte senseCmd[] = { 0x03, 0x00, 0x00, 0x00, 20, 0 };

int
SCSIOpen(chan)
Chan *chan;
{
    int error;

    chan->ch_Ios.sr_Req.io_Message.mn_ReplyPort = IoSink;
    chan->ch_Ios.sr_Req.io_Message.mn_Node.ln_Name = (char *)chan;
    if (error = OpenDevice(chan->ch_DeviceName, chan->ch_UnitNo, (IORequest *)&chan->ch_Ios, 0)) {
	chan->ch_Ios.sr_Req.io_Device = NULL;
	error = -1;
    } else {
	DoSCSI(chan, senseCmd, NULL, 0, SCSIF_READ, NULL);
    }
    return(error);
}

void
SCSIClose(chan)
Chan *chan;
{
    if (chan->ch_Ios.sr_Req.io_Device) {
	if (chan->ch_Flags & CHANF_IOSIP) {
	    AbortIO((IORequest *)&chan->ch_Ios);
	    WaitIO((IORequest *)&chan->ch_Ios);
	    chan->ch_Flags &= ~CHANF_IOSIP;
	}
	CloseDevice((IORequest *)&chan->ch_Ios);
	chan->ch_Ios.sr_Req.io_Device = NULL;
    }
}

int
DoSCSI(chan, cmd, buf, bytes, flags, plen)
Chan *chan;
char *cmd;
char *buf;
long bytes;
ubyte flags;
long *plen;
{
    SendSCSI(chan, cmd, buf, bytes, flags);
    return(WaitSCSI(chan, plen));
}

void
SendSCSI(chan, cmd, buf, bytes, flags)
Chan *chan;
char *cmd;
char *buf;
long bytes;
ubyte flags;
{
    SCSIReq *ios = &chan->ch_Ios;

    movmem(cmd, chan->ch_Cmd, 6);

    ios->sr_Cmd.scsi_Command   = chan->ch_Cmd;
    ios->sr_Cmd.scsi_CmdLength = 6;
    ios->sr_Cmd.scsi_Data   = buf;
    ios->sr_Cmd.scsi_Length = bytes;
    ios->sr_Cmd.scsi_Flags  = flags;

    ios->sr_Req.io_Command = 28;
    ios->sr_Req.io_Data    = &ios->sr_Cmd;
    ios->sr_Req.io_Length  = sizeof(ios->sr_Cmd);

    SendIO((IORequest *)&ios->sr_Req);
    chan->ch_IosLen = bytes;
    chan->ch_Flags |= CHANF_IOSIP;
}

int
WaitSCSI(chan, plen)
Chan *chan;
long *plen;
{
    SCSIReq *ios = &chan->ch_Ios;
    ubyte senseBuf[20];
    int error;

    if (chan->ch_Flags & CHANF_IOSIP) {
	WaitIO((IORequest *)&ios->sr_Req);
	chan->ch_Flags &= ~CHANF_IOSIP;
    }

    if (plen)
	*plen = ios->sr_Cmd.scsi_Actual;

    switch (error = ios->sr_Req.io_Error) {
    case 0:
	break;
    case HFERR_BadStatus:
	ios->sr_Cmd.scsi_Command   = senseCmd;
	ios->sr_Cmd.scsi_CmdLength = 6;
	ios->sr_Cmd.scsi_Data	= (UWORD *)senseBuf;
	ios->sr_Cmd.scsi_Length = sizeof(senseBuf);
	ios->sr_Cmd.scsi_Flags	= SCSIF_READ;

	if (DoIO((IORequest *)&ios->sr_Req)) {
	    error = -256;
	    break;
	}
	if (ios->sr_Cmd.scsi_Actual < 4) {
	    error = -257;
	    break;
	}
	error = senseBuf[2];
	if (error == SENSE_RECOVERED_ERROR && ios->sr_Cmd.scsi_Actual == chan->ch_IosLen)
	    error = 0;
	break;
    default:
	error = -error;
	break;
    }
    if (error)
	printf("SCSI CMD %d ERROR %d\n", chan->ch_Cmd[0], error);
    return(error);
}

