
#include "unix.h"
#include "extern.h"

#define LUN 0
#define RDCMD 0x8
#define WRCMD 0xa

static char cmdblk[6] = { 0, LUN<<5, 0, 0, 0, 0 }; 

extern char *dptrlo;
extern pageaddr dptrhi;
extern unsigned dlen;
extern char *cptr;
extern int busid;
extern scsiop();


wd_read(minor, rawflag)
unsigned minor;
int rawflag;
{
    cmdblk[0] = RDCMD;
    if (setup(minor, rawflag))
	return(0);

    chkstat(scsiop(),1);
    return(cmdblk[4] << 9);
}

wd_write(minor, rawflag)
unsigned minor;
int rawflag;
{
    cmdblk[0] = WRCMD;
    if (setup(minor, rawflag))
 	return(0);

    chkstat(scsiop(),0);

    return(cmdblk[4] << 9);
}

static blkno_t block;


static
setup(minor, rawflag)
unsigned minor;
int rawflag;
{

    cptr = cmdblk;
    busid = 1;

    switch (rawflag)
    {

	case 2:

	    /* Paging */
            cmdblk[4] = swapcnt >> 9;
	    dlen = swapcnt;
	    dptrhi = swapbase;
	    dptrlo = 0;
            block = swapblk;
	    break;

	case 1:

	    /* Raw I/O (broken) */
            cmdblk[4] = udata.u_count >> 9;
	    dlen = udata.u_count;
  	    dptrlo = udata.u_base;
	    dptrhi = padr(1, dptrlo);
            block = udata.u_offset.o_blkno;
	    break;

	case 0:

	    cmdblk[4] = 1;
	    dlen = 512;
	    dptrlo = udata.u_buf->bf_data;
	    dptrhi = padr(0, dptrlo);
	    block = udata.u_buf->bf_blk;
	    break;

	default:
	    panic("wd case");

    }


    block += (minor & 0xff00);
/*
    if (block > (minor << 8))
    {
	if (cmdblk[0] == WRCMD)
	    udata.u_error = ENXIO;
	return (1);
    }
*/

    cmdblk[3] = block;
    cmdblk[2] = block >> 8;
    return(0);
}


static
chkstat(stat, rdflag)
int stat;
int rdflag;
{

    if (stat)
    {
	kprintf("\nwd %s failure block %x dptr %x:%x dlen %x stat %x\n",
		 rdflag ? "read": "write", block, dptrhi, dptrlo,
		 dlen, stat);
	perror();
	panic("");
    }
}




static char *errcodes[] = {

	"No error",
	"No index signal",
	"No seek complete",
	"Drive fault",
	"Drive not ready",
	0,
	"No track 00",
	0,
	0,
	0,
	0,
	0,
	"Write fault",
	0,
	0,
	0,
	"ID CRC error",
	"Uncorrectable data error",
	0,
	"Data address mark not found",
	"Record not found",
	"Seek error",
	0,
	0,
	"Corrected data error",
	0,
	"Format error",
	0,
	0,
	0,
	0,
	0,
	"Invalid command",
	"Illegal block address",
	"Command aborted",
	"Invalid parameters",
	0,
	"Controller error",
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0  };



static perror()
{
    int n;
    static char cmd[] = { 3, 0, 0, 0, 4, 0 };
    static char erstat[4];

    busid = 1;
    cptr = cmd;
    dptrlo = erstat;
    dptrhi = padr(1, erstat);
    dlen = 4;

    scsiop();

    n = erstat[0] & 0x7f;

    if (n<0 || n >= 48)
	kprintf("Invalid error code\n");
    else if (errcodes[n] == 0)
	kprintf("Unknown error code %x\n",n);
    else
  	kprintf("Error %x: %s\n",n,errcodes[n]);
}




wd_open(minor)
int minor;
{
    return(0);
}


/* The following is generic SCSI driver code, also used by devmt.c */
/* Version of 5/89 with latest Z280 UNIX SCSI driver code  */
/* Version of 9/89 that works with TPA in physcial memory at C00000h
   for CP/M 3  */


char *dptrlo;
pageaddr dptrhi;
unsigned dlen;
char *cptr;
int busid;

scsiop()
{

#asm 8080

;
SDATA	EQU	0D8H
SCMD	EQU	0D9H
;
;
;ENTRY POINT:
;
	PUSH	B
;
LOOP1:	CALL	SWAIT
	JZ	HUNG	;ABORT IF PENDING TRANSACTION

	LDA	busid?	;OUTPUT SCSI BUS ADDRESS
	OUT	SDATA
	MVI	A,1	;SELECT CONTROLLER
	OUT	SCMD	;ASSERT SELECT
..A2:	IN	SCMD	;WAIT FOR BSY TO BE ASSERTED
	ANI	01
	JNZ	..A2
	XRA	A
	OUT	SCMD	;DEASSERT IT
;
	LHLD	cptr?
.LOOP2:	CALL	SWAIT	;WAIT FOR REQ
	JNZ	LOST
	IN	SCMD
	ANI	1FH
	CPI	01100B	;CONTINUE AS LONG AS IT WANTS COMMANDS
	JNZ	ECMD
	ANI	00100B
	JZ	SEQ	;ABORT IF IT HAS A MESSAGE
	MOV	A,M		;TRANSMIT COMMAND
	OUT	SDATA
	INX	H
	JMP	.LOOP2
;	
ECMD:	LHLD	dlen?
	MOV	A,H
	ORA	L
	JZ	EDATA	;SKIP DATA I/O IF NECESSARY
	CALL	SWAIT	
	JNZ	LOST
	IN	SCMD	;SEE IF IT REALLY WANTS DATA
	ANI	10H
	JZ	EDATA
	IN	SCMD
	ANI	08H	;CHECK FOR DATA READ OR WRITE
	JNZ	WIO
	
	; FILL IN THE DMA PROGRAM WITH THE CORRECT ADDRESS AND LENGTH
	LHLD	dptrlo?
	SHLD	RDADR

	lhld	dptrhi?
	shld	rdadr+2

	LHLD	dlen?
	SHLD	RDCNT
;
	;SEND PROGRAM TO DMA CONTROLLER
	MVI	A,08
	LXI	H, RDBLK
	CALL	DODMA
	JMP	EDATA
;
WIO:
	LHLD	dptrlo?
	SHLD	WRADR
	lhld	dptrhi?
	shld	wradr+2

	LHLD	dlen?
	SHLD	WRCNT
;
	MVI	A,08
	LXI	H,WRBLK
	;SEND PROGRAM TO DMA CONTROLLER
	CALL	DODMA	
	JMP	EDATA

DODMA:
	PUSH	H
	PUSH	PSW
	CALL	IOPGFF?##    ;This disables interrupts
	POP	PSW
	POP	H
	MOV	C,A
	MVI	B,6
..LOOP:	OUTIW
	INR	C
	INR	B
	DCR	B
	JNZ	..LOOP
	CALL	IOPG00?##	;This restores interrupts
	RET


;
EDATA:
	CALL	SWAIT	;WAIT UNTIL THE CONTROLLER WANTS TO SEND NON-DATA
	JNZ	LOST
	IN	SCMD
	ANI	10H
	JNZ	EDATA
;
;GET STATUS AND SHUT DOWN
;

	IN	SCMD
	ANI	1FH
	CPI	00100B
	JNZ	SEQ	;JUMP IF IT DOESN'T WANT TO SEND STATUS
;
	IN	SDATA
	MOV	L,A
	MVI	H,0
	CALL	SWAIT
	JNZ	LOST
	IN	SCMD
	ANI	1FH
	CPI	00000B
	JNZ	SEQ
	IN	SDATA	;READ FINAL MESSAGE BYTE
;
DONE:	POP	B
	MOV	A,H
	ORA	L
	RET
;
;
LOST:	LXI	H,-1
	JMP	DONE
;
SEQ:	CALL	SWAIT
	LXI	H,-2
	JNZ	DONE
	IN	SDATA	;EAT EXTRA DATA
	JMP	SEQ
;
HUNG:
	CALL	WRESET
	LXI	H,-3
	JMP	DONE
;
; THIS WAITS FOR REQ TO BE ASSERTED OR FOR THE CONNECTION TO BE LOST.
;A NON-ZERO RETURN MEANS CONNECTION WAS LOST
;
SWAIT:
	IN	SCMD
	ANI	01
	RNZ		;RETURN IF NOT EVEN BUSY
	IN	SCMD
	ANI	22H	;MASK OUT REQ AND MAKE SURE ACK FROM LAST CYCLE IS GONE
	JNZ	SWAIT
	RET
;
WRESET:
	MVI	A,2
	OUT	SCMD
	XTHL
	XTHL
	XTHL
	XTHL
	XRA	A
	OUT	SCMD
	RET
;	
;
; THESE ARE THE DMA PROGRAMS FOR READ/WRITE
;
RDBLK:	
RDADR:	DW	000
	DW	000
	DW	SDATA
	DW	0000
RDCNT:	DW	000
	DW	0E080H

WRBLK:
	DW	SDATA
	DW	0000
WRADR:	DW	000	
	DW	000	
WRCNT:	DW	000	
	DW	0808CH



#endasm
	
}
 
 