对于先前分配的包含待传送数据的包,tran_init_pkt(9E) 入口点在满足以下条件时必须重新分配 DMA 资源:
已分配部分 DMA 资源。
先前调用 tran_init_pkt(9E) 时返回了非零的 pkt_resid。
bp 不为 null。
bp->b_bcount 不为零。
重新分配下一个传送部分的 DMA 资源时,tran_init_pkt(9E) 必须在字段 pkt_resid 中返回未为此传送分配的 DMA 资源量。
如果在尝试移动 DMA 资源时出现错误,则 tran_init_pkt(9E) 决不能释放 scsi_pkt(9S)。在这种情况下,目标驱动程序负责释放包。
如果回调参数为 NULL_FUNC,则 tran_init_pkt(9E) 入口点决不能休眠或调用可能会休眠的任何函数。如果回调参数为 SLEEP_FUNC 并且资源不会立即可用,则 tran_init_pkt(9E) 入口点会休眠。除非无法满足请求,否则 tran_init_pkt() 将休眠,直到资源可用为止。
static int
isp_i_dma_move(
struct isp *isp,
struct scsi_pkt *pkt,
struct buf *bp)
{
struct isp_cmd *sp = (struct isp_cmd *)pkt->pkt_ha_private;
int i;
ASSERT(sp->cmd_flags & CFLAG_COMPLETED);
sp->cmd_flags &= ~CFLAG_COMPLETED;
/*
* If there are no more cookies remaining in this window,
* must move to the next window first.
*/
if (sp->cmd_cookie == sp->cmd_ncookies) {
/*
* For small pkts, leave things where they are
*/
if (sp->cmd_curwin == sp->cmd_nwin && sp->cmd_nwin == 1)
return (1);
/*
* At last window, cannot move
*/
if (++sp->cmd_curwin >= sp->cmd_nwin)
return (0);
if (ddi_dma_getwin(sp->cmd_dmahandle, sp->cmd_curwin,
&sp->cmd_dma_offset, &sp->cmd_dma_len,
&sp->cmd_dmacookies[0], &sp->cmd_ncookies) ==
DDI_FAILURE)
return (0);
sp->cmd_cookie = 0;
} else {
/*
* Still more cookies in this window - get the next one
*/
ddi_dma_nextcookie(sp->cmd_dmahandle,
&sp->cmd_dmacookies[0]);
}
/*
* Get remaining cookies in this window, up to our maximum
*/
i = 0;
for (;;) {
sp->cmd_dmacount += sp->cmd_dmacookies[i++].dmac_size;
sp->cmd_cookie++;
if (i == ISP_NDATASEGS ||
sp->cmd_cookie == sp->cmd_ncookies)
break;
ddi_dma_nextcookie(sp->cmd_dmahandle,
&sp->cmd_dmacookies[i]);
}
sp->cmd_cookiecnt = i;
pkt->pkt_resid = bp->b_bcount - sp->cmd_dmacount;
return (1);
}