Writing Device Drivers

Reallocation of DMA Resources for Next Portion of Data Transfer

For a previously allocated packet with data remaining to be transferred, the tran_init_pkt(9E) entry point must reallocate DMA resources when the following conditions apply:

When reallocating DMA resources to the next portion of the transfer, tran_init_pkt(9E) must return the amount of DMA resources not allocated for this transfer in the field pkt_resid.

If an error occurs while attempting to move DMA resources, tran_init_pkt(9E) must not free the scsi_pkt(9S). The target driver in this case is responsible for freeing the pkt.

If the callback parameter is NULL_FUNC, the tran_init_pkt(9E) entry point must not sleep or call any function which may sleep. If the callback parameter is SLEEP_FUNC and resources are not immediately available, the tran_init_pkt(9E) entry point should sleep until resources are available, unless the request is impossible to satisfy.


Example 14-6 HBA Driver DMA Resource Reallocation

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);
}