u64_t position, iovec_t *iov, unsigned nr_req) );
FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
FORWARD _PROTOTYPE( int com_out_ext, (struct command *cmd) );
-FORWARD _PROTOTYPE( void setup_dma, (unsigned *sizep, endpoint_t proc_nr,
- iovec_t *iov, size_t addr_offset, int do_write,
- int *do_copyoutp) );
+FORWARD _PROTOTYPE( int setup_dma, (unsigned *sizep, endpoint_t proc_nr,
+ iovec_t *iov, size_t addr_offset, int do_write) );
FORWARD _PROTOTYPE( void w_need_reset, (void) );
FORWARD _PROTOTYPE( void ack_irqs, (unsigned int) );
FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
{
struct wini *wn = w_wn;
iovec_t *iop, *iov_end = iov + nr_req;
- int n, r, s, errors, do_dma, do_write, do_copyout;
+ int n, r, s, errors, do_dma, do_write;
unsigned long block, w_status;
u64_t dv_size = w_dv->dv_size;
unsigned nbytes;
if (do_dma) {
stop_dma(wn);
- setup_dma(&nbytes, proc_nr, iov, addr_offset, do_write,
- &do_copyout);
+ if (!setup_dma(&nbytes, proc_nr, iov, addr_offset, do_write)) {
+ do_dma = 0;
+ }
#if 0
printf("nbytes = %d\n", nbytes);
#endif
if (n > nbytes)
n= nbytes;
- if (do_copyout)
- {
- if(proc_nr != SELF) {
- s= sys_safecopyto(proc_nr, iov->iov_addr,
- addr_offset,
- (vir_bytes)(dma_buf+dma_buf_offset),
- n, D);
- if (s != OK) {
- panic("w_transfer: sys_safecopy failed: %d", s);
- }
- } else {
- memcpy((char *) iov->iov_addr + addr_offset,
- dma_buf + dma_buf_offset, n);
- }
- }
-
/* Book the bytes successfully transferred. */
nbytes -= n;
position= add64ul(position, n);
/*===========================================================================*
* setup_dma *
*===========================================================================*/
-PRIVATE void setup_dma(sizep, proc_nr, iov, addr_offset, do_write,
- do_copyoutp)
+PRIVATE int setup_dma(sizep, proc_nr, iov, addr_offset, do_write)
unsigned *sizep;
endpoint_t proc_nr;
iovec_t *iov;
size_t addr_offset;
int do_write;
-int *do_copyoutp;
{
- phys_bytes phys, user_phys;
+ phys_bytes user_phys;
unsigned n, offset, size;
- int i, j, r, bad;
+ int i, j, r;
unsigned long v;
struct wini *wn = w_wn;
int verbose = 0;
size= *sizep;
i= 0; /* iov index */
j= 0; /* prdt index */
- bad= 0;
offset= 0; /* Offset in current iov */
if(verbose)
{
/* Buffer is not aligned */
printf("setup_dma: user buffer is not aligned\n");
- bad= 1;
- break;
+ return 0;
}
/* vector is not allowed to cross a 64K boundary */
if (j >= N_PRDTE)
{
/* Too many entries */
-
- bad= 1;
- break;
+ printf("setup_dma: user buffer has too many entries\n");
+ return 0;
}
prdt[j].prdte_base= user_phys;
size -= n;
}
- if (!bad)
- {
if (j <= 0 || j > N_PRDTE)
panic("bad prdt index: %d", j);
prdt[j-1].prdte_flags |= PRDTE_FL_EOT;
prdt[i].prdte_flags);
}
}
- }
-
- /* The caller needs to perform a copy-out from the dma buffer if
- * this is a read request and we can't DMA directly to the user's
- * buffers.
- */
- *do_copyoutp= (!do_write && bad);
-
- if (bad)
- {
- if(verbose)
- printf("partially bad dma\n");
- /* Adjust request size */
- size= *sizep;
- if (size > ATA_DMA_BUF_SIZE)
- *sizep= size= ATA_DMA_BUF_SIZE;
-
- if (do_write)
- {
- /* Copy-in */
- for (offset= 0; offset < size; offset += n)
- {
- n= size-offset;
- if (n > iov->iov_size)
- n= iov->iov_size;
-
- if(proc_nr != SELF) {
- r= sys_safecopyfrom(proc_nr, iov->iov_addr,
- addr_offset, (vir_bytes)dma_buf+offset,
- n, D);
- if (r != OK) {
- panic("setup_dma: sys_safecopy failed: %d", r);
- }
- } else {
- memcpy(dma_buf + offset,
- (char *) iov->iov_addr + addr_offset,
- n);
- }
- iov++;
- addr_offset= 0;
- }
- }
-
- /* Fill-in the physical region descriptor table */
- phys= dma_buf_phys;
- if (phys & 1)
- {
- /* Two byte alignment is required */
- panic("bad buffer alignment in setup_dma: 0x%lx", phys);
- }
- for (j= 0; j<N_PRDTE; i++)
- {
- if (size == 0) {
- panic("bad size in setup_dma: %d", size);
- }
- if (size & 1)
- {
- /* Two byte alignment is required for size */
- panic("bad size alignment in setup_dma: %d", size);
- }
- n= size;
-
- /* Buffer is not allowed to cross a 64K boundary */
- if (phys / 0x10000 != (phys+n-1) / 0x10000)
- {
- n= ((phys/0x10000)+1)*0x10000 - phys;
- }
- prdt[j].prdte_base= phys;
- prdt[j].prdte_count= n;
- prdt[j].prdte_reserved= 0;
- prdt[j].prdte_flags= 0;
-
- size -= n;
- if (size == 0)
- {
- prdt[j].prdte_flags |= PRDTE_FL_EOT;
- break;
- }
- }
- if (size != 0)
- panic("size to large for prdt");
-
- if(verbose) {
- for (i= 0; i<=j; i++)
- {
- printf("prdt[%d]: base 0x%x, size %d, flags 0x%x\n",
- i, prdt[i].prdte_base, prdt[i].prdte_count,
- prdt[i].prdte_flags);
- }
- }
- }
/* Verify that the bus master is not active */
r= sys_inb(wn->base_dma + DMA_STATUS, &v);
r= sys_outb(wn->base_dma + DMA_STATUS, DMA_ST_INT | DMA_ST_ERROR);
if (r != 0) panic("setup_dma: sys_outb failed: %d", r);
+ return 1;
}
packet[11] = 0;
if(do_dma) {
- int do_copyout = 0;
stop_dma(wn);
- setup_dma(&nbytes, proc_nr, iov, addr_offset, 0,
- &do_copyout);
- if(do_copyout || (nbytes != nblocks * CD_SECTOR_SIZE)) {
+ if (!setup_dma(&nbytes, proc_nr, iov, addr_offset, 0)) {
+ do_dma = 0;
+ } else if(nbytes != nblocks * CD_SECTOR_SIZE) {
stop_dma(wn);
do_dma = 0;
}