[ncr.sys.unix] Problem with DDI/DDK DMA for UNIX SVR4

shung@riipsdev.Waterloo.NCR.Com (Simon Hung) (06/07/91)

I have been trying to use the DMA functions found in the DDI/DKI of UNIX 
System V Release 4.  So far, I have been unsuccessful.  Any help to 
determine the origin of my problem would be greatly appreciated.

My objective is to write a SCSI device driver for a in-house designed SCSI
board and to use the DMA to transfer data between the SCSI hardware and
kernel memory. Please note, I have managed to program the DMA hardware
directly and made successful transfers, so the hardware is OK.

The following program illustrates how I use the DDI/DKI's dma functions :

/* -------------------------------------------------------------------------*/

#define CHANNEL_3	3			/* DMA channel no. 	*/
#define	BUFSIZE		50000		/* User buffer size 	*/

char	*user_buf;
struct	dma_db	db1, db2;
struct	dma_cb	cb;

	/* Allocate user buffer */
	user_buf = mem_alloc ( BUFSIZE, KM_SLEEP );

	/* Allocate dma target and request buffer */
	db1 = dma_get_buf ( DMA_SLEEP );
	db2 = dma_get_buf ( DMA_SLEEP );

	/* Allocate dma control block */
	cb = dma_get_cb ( DMA_SLEEP );

	/* Set up target and request buffer */
	db1->address	= kvtophys ( user_buf );
	db1->count	= message_length;

	db2->address	= 0x410;		/* scsi DMA port address */
	db2->count 	= message_length;

	/* Set up dma control block */
	cb->targbufs 	= db1;
	cb->reqrbufs 	= db2;
	cb->command	= DMA_CMD_WRITE;
	cb->targ_type	= DMA_TYPE_MEM;
	cb->reqr_type	= DMA_TYPE_IO;
	cb->targ_step	= DMA_STEP_INC;
	cb->reqr_step	= DMA_STEP_HOLD;
	cb->trans_type	= DMA_TRANS_BLCK;
	cb->targ_path	= DMA_PATH_8;
	cb->reqr_step	= DMA_PATH_8;
	cb->cycles	= DMA_CYCLES_1;
	cb->bufprocess	= DMA_BUF_SNGL;

	dma_disable ( CHANNEL_3 );
	if ( dma_prog ( cb, CHANNEL_3, DMA_NOSLEEP)==0 )
	{
		dma_enable ( CHANNEL_3 );
		/**********************************************************
		When program reaches this point, the system is crash and
		prints - Unexpected NMI in system mode.
		***********************************************************/

/* ------------------------------------------------------------------------ */

I am using a MCA 386sx machine. Here is the way I program the DMA directly
using DMA extended function register :

#define	FREG	0x18
#define	EFREG	0x1a

	paddr_t	address;
	int	io_address;

	/* Mask off channel 3 */
	outb ( FREG, 0x93 );

	/* Select mode register */
	outb ( FREG, 0x73 );

	/* Write mode register :
		- Write memory transfer
		- Data Transfer Operation
		- Use programmed I/O address
	*/
	outb ( EFREG, 0xd );

	/* Select memory address register */
	outb ( FREG, 0x23 );

	/* Set up target address */
	address = kvtophys ( user_buf );
	outb ( EFREG, address );
	outb ( EFREG, address>>8 );
	outb ( EFREG, address>>16 );

	/* Select I/O address register */
	outb ( FREG, 0x43 );

	/* Set up I/O address */
	io_address = 0x410;
	outb ( EFREG, io_address );
	outb ( EFREG, io_addess>>8 );

	/* Select Transfer Count register */
	outb ( FREG, 0x43 );

	/* Set up Transfer Count */
	outb ( EFREG, message_length );
	outb ( EFREG, message_length>>8 );

	/* Unmask channel 3 */
	outb ( FREG, 0xa3 );

/* --------------------------------------------------------------------------*/

Your advice is appreciated and I'm looking forward to hearing from someone.


Regards,
Simon Hung