The strategy(9E) routine originated in block drivers and is so called because it can implement 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 Example 10-8, the strategy(9E) routine for a character-oriented DMA device allocates DMA resources for synchronous data transfer and starts the command by programming the device register (see Chapter 8, Direct Memory Access (DMA) for a detailed description).
strategy(9E) does not receive a device number (dev_t) as a parameter; instead, this 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 ddi_dev_is_needed(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(9E) is declared to return an int, it must always return zero.
On completion of the DMA transfer, the device generates an interrupt, causing the interrupt routine to be called. In Example 10-9, 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).