The strategy(9E) routine originated in block drivers. The strategy function got its name from implementing a strategy for efficient queuing of I/O requests to a block device. A driver for a character-oriented device can also use a strategy(9E) routine. In the character I/O model presented here, strategy(9E) does not maintain a queue of requests, but rather services one request at a time.
In the following example, the strategy(9E) routine for a character-oriented DMA device allocates DMA resources for synchronous data transfer. strategy() starts the command by programming the device register. See Chapter 9, Direct Memory Access (DMA) for a detailed description.
strategy(9E) does not receive a device number (dev_t) as a parameter. Instead, the device number is retrieved from the b_edev field of the buf(9S) structure passed to strategy(9E).
static int xxstrategy(struct buf *bp) { minor_t instance; struct xxstate *xsp; ddi_dma_cookie_t cookie; instance = getminor(bp->b_edev); xsp = ddi_get_soft_state(statep, instance); /* ... */ * If the device has power manageable components, * mark the device busy with pm_busy_components(9F), * and then ensure that the device is * powered up by calling pm_raise_power(9F). */ /* Set up DMA resources with ddi_dma_alloc_handle(9F) and * ddi_dma_buf_bind_handle(9F). */ xsp->bp = bp; /* remember bp */ /* Program DMA engine and start command */ return (0); }
Although strategy() is declared to return an int, strategy() must always return zero.
On completion of the DMA transfer, the device generates an interrupt, causing the interrupt routine to be called. In the following example, xxintr() receives a pointer to the state structure for the device that might have generated the interrupt.
static u_int xxintr(caddr_t arg) { struct xxstate *xsp = (struct xxstate *)arg; if ( /* device did not interrupt */ ) { return (DDI_INTR_UNCLAIMED); } if ( /* error */ ) { /* error handling */ } /* Release any resources used in the transfer, such as DMA resources. * ddi_dma_unbind_handle(9F) and ddi_dma_free_handle(9F) * Notify threads that the transfer is complete. */ biodone(xsp->bp); return (DDI_INTR_CLAIMED); }
The driver indicates an error by calling bioerror(9F). The driver must call biodone(9F) when the transfer is complete or after indicating an error with bioerror(9F).