/*
	@(#)msc.c	1.3	(8/7/84 12:45:52)
*/
#include "standalone.h"

/* #define	DEBUG	1 */

#define MBIOBASE	0x1FF800 		/* Start of MULTIBUS I/O.    */

#define MSCCMDP_VA	(MBIOBASE + 0x0080)	/* I/O ports base address.   */
#define MSCIOPB_VA	(localipb)		/* I/O parameter block addr. */
#define MSCDBUF_VA	(localbuf)		/* Multibus buffer address.  */

#define	vtop(p)		((int)(p))

#define	MSC_SEEK	1
#define MSC_READ        4
#define MSC_WRITE       6
#define MSC_INTC        0x00
#define MSC_OK          0x00
#define MSC_LN16        0x08
#define MSC_BUSY        0x80


typedef struct                  /* THE READ I/O PORTS.                  */
        {                       /* ==================================== */
        U8      msc_rrt;        /* 0x01: Read result type.              */
        U8      msc_rss;        /* 0x00: Read subsystem status.         */
        U8      msc_rrb;        /* 0x03: Read result byte.              */
        U8      msc_rcs;        /* 0x02: Read controller status.        */
        U8      msc_rs5;        /* 0x05: Reserved.                      */
        U8      msc_ris;        /* 0x04: Read interrupt status.         */
        U8      msc_rdc;        /* 0x07: Read disk configuration.       */
        U8      msc_rs6;        /* 0x06: Reserved.                      */
        }       MSC_R;          /* ==================================== */

typedef struct                  /* THE WRITE I/O PORTS.                 */
        {                       /* ==================================== */
        U8      msc_wlo;        /* 0x01: Write low-order IOPB address.  */
        U8      msc_wsm;        /* 0x00: Write segment memory address.  */
        U8      msc_ws3;        /* 0x03: Reserved.                      */
        U8      msc_who;        /* 0x02: Write high-order IOPB addr.    */
        U8      msc_wsd;        /* 0x05: Start diagnostic.              */
        U8      msc_ws4;        /* 0x04: Reserved.                      */
        U8      msc_wrc;        /* 0x07: Clear and reset the controller.*/
        U8      msc_ws6;        /* 0x06: Reserved.                      */
        }       MSC_W;          /* ==================================== */

typedef union                   /* THE READ AND WRITE I/O PORTS.        */
        {                       /* ==================================== */
        MSC_R   msc_r;          /* The READ I/O ports.                  */
        MSC_W   msc_w;          /* The WRITE I/O ports.                 */
        }       MSC;            /* ==================================== */

typedef struct                  /* THE I/O PARAMETER BLOCK.             */
        {                       /* ==================================== */
        U8      msc_disk;       /* 0x01: Disk instruction.              */
        U8      msc_intc;       /* 0x00: Interrupt control.             */
        U8      msc_cyln;       /* 0x03: Cylinder number.               */
        U8      msc_rcnt;       /* 0x02: Record count.                  */
        U8      msc_offl;       /* 0x05: Offset address, low byte.      */
        U8      msc_radr;       /* 0x04: Record address.                */
        U8      msc_segl;       /* 0x07: Segment address, low byte.     */
        U8      msc_offh;       /* 0x06: Offset address, high byte.     */
        U8      msc_crty;       /* 0x09: Command retry temporary.       */
        U8      msc_segh;       /* 0x08: Segment address, high byte.    */
        }       MSC_IOPB;       /* ==================================== */

static	U8     *localipb;
static	U8     *localbuf;
U8		msczero;

mscdone(command)
	int	command;
	{
	register  MSC  *ioports;
	register  int   loop;
	register  int   loopmax;
	unsigned  char  result1;
	unsigned  char  result3;

	ioports = (MSC *)MSCCMDP_VA;
        for (loop = 0, loopmax = 1000000;  loop < loopmax;  loop++)
            {
            if ((ioports->msc_r.msc_rcs & MSC_BUSY) == 0)
                {
                break;
                }
            }
        if (loop == loopmax)
            {
            printf("msc: BUSY TIMEOUT OF %d, CONTINUING.\n",loop);
            }
        result1 = ioports->msc_r.msc_rrt;
        result3 = ioports->msc_r.msc_rrb;
	/*
	 *  Since the seek command is normally only used for the ship
	 *  function, we want to ignore the error 5 condition, which
	 *  occurs when a seek to a ship track finds that the ship track
	 *  has not been formatted. To save code space, we simply ignore
	 *  all errors that occur when doing a seek.
	 */
        if (result3 != MSC_OK  &&  command != MSC_SEEK)
	    {
	    printf("msc: error %x %x\n",result1,result3);
	    }
	}

msccmd(drive,command,steprate,address,cylinder,head,sector,sectrcnt)
        U32     drive;
        U32     command;
        U32     steprate;
        U32     address;
        U32     cylinder;
        U32     head;
        U32     sector;
        U32     sectrcnt;
        {
        register  MSC       *ioports;
        register  MSC_IOPB  *iopb;
        register  U32        iopb_pa;
	register  U32	     paddr;
	register  U32	     initloop;
	static    U32        firsttime = 1;
        U8	ipb_segl;
        U8	ipb_segh;
        U8	ipb_offl;
        U8	ipb_offh;

#ifdef	DEBUG
	printf("msc: cmd entry\n");
	printf("MSC DEBUG: drive:%x command:%x steprate:%x address:%x\n",
               drive,command,steprate,address);
	printf("MSC DEBUG: cylinder:%x head:%x sector:%x sectrcnt:%x\n",
	       cylinder,head,sector,sectrcnt);
#endif
	if (firsttime)
	    {
            for (initloop = 0;  initloop < 8;  initloop++)
                {
                ioports->msc_w.msc_wrc = 0;
	        mscdone(99999);
                }
	    firsttime = 0;
	    }
        iopb = (MSC_IOPB *)MSCIOPB_VA;
        ioports = (MSC *)MSCCMDP_VA;
	mscdone(99999);
	paddr = vtop(MSCDBUF_VA);
        iopb->msc_disk = head << 6 | (drive << 4) | (head & 4) << 1 | command;
        iopb->msc_intc = 0x10 | MSC_LN16 | steprate;
        iopb->msc_cyln = cylinder;
        iopb->msc_radr = sector & 0x3f  |  ((cylinder >> 2) & 0xc0);
        iopb->msc_rcnt = sectrcnt;
        iopb->msc_segl = paddr >> 4;
        iopb->msc_segh = paddr >> 12;
        iopb->msc_offl = paddr & 0x0f;
        iopb->msc_offh = 0;
        iopb_pa = vtop(iopb);
        ipb_segl = iopb_pa >> 4;
        ipb_segh = iopb_pa >> 12;
        ipb_offl = iopb_pa & 0x0f;
        ipb_offh = 0;
        ioports->msc_w.msc_wlo = ipb_offl;	/* low off addr */
        ioports->msc_w.msc_wsm = ipb_segl;	/* low seg addr */
        ioports->msc_w.msc_wsm = ipb_segh;	/* hi  seg addr */
        ioports->msc_w.msc_who = ipb_offh;	/* hi  off addr */
	mscdone(command);
	if (command == MSC_READ)
	    {
	    bcopy(MSCDBUF_VA,address,sectrcnt<<9);
	    }
	}

mscio(diob)
	register DIOB  *diob;
        {
	register  int	cylinder;
	register  int	track;
	register  int	sector;
	register  int   nbpt;
	register  int	nbpc;
	register  int	ablock;
	register  int   steprate;
	register  int   drive;
	register  int   seccnt;
	register  U8   *address;
	U8		lipb[sizeof(MSC_IOPB)+4];
	U8		lbuf[1024];
	static	int	count = 1;

	localbuf = lbuf;
	localipb = lipb;
#ifdef	DEBUG
	printf("\n\nENTRY=%d\nmscio: desired block = %d\n",
               count++,diob->diob_fdb);
	printf("mscio: buffer = %x, iopb = %x\n",localbuf,localipb);
#endif
	nbpt     = diob->diob_dbt;
	nbpc     = nbpt * diob->diob_dtc;
	ablock   = diob->diob_fsb + diob->diob_fdb;
        cylinder = ablock / nbpc;
        track    = ablock % nbpc / nbpt;
        sector   = ablock % nbpt + 1;
	drive    = diob->diob_drv;
	steprate = diob->diob_dp1;
	address  = diob->diob_buf;
	seccnt   = diob->diob_nblks;
	msccmd(drive,MSC_READ,steprate,address,cylinder,track,sector,seccnt);
#ifdef	DEBUG
	printf("mscio: i/o done\n");
#endif
	retunr (0);
	}

mscship(drive,cylinder)
	int	drive;
	int	cylinder;
	{

        msccmd(drive,MSC_SEEK,0,0,cylinder,0,0,0);
	}
