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