History

block: implement drain buffers

These DMA drain buffer implementations in drivers are pretty horrible to do in terms of manipulating the scatterlist. Plus they're being done at least in drivers/ide and drivers/ata, so we now have code duplication. The one use case for this, as I understand it is AHCI controllers doing PIO mode to mmc devices but translating this to DMA at the controller level. So, what about adding a callback to the block layer that permits the adding of the drain buffer for the problem devices. The idea is that you'd do this in slave_configure after you find one of these devices. The beauty of doing it in the block layer is that it quietly adds the drain buffer to the end of the sg list, so it automatically gets mapped (and unmapped) without anything unusual having to be done to the scatterlist in driver/scsi or drivers/ata and without any alteration to the transfer length.

James Bottomley committed 18 years ago

Commit fa0ccd81 parent 5d840703 files · +78 −1Browse files

Unified · Split

3 files
  1. block/elevator.c +25 −1
  2. block/ll_rw_blk.c +49 −0
  3. include/linux/blkdev.h +4 −0
block/elevator.c+25−1
@@ -741,7 +741,21 @@ struct request *elv_next_request(struct request_queue *q) · 740 unmodified lines
741741 q->boundary_rq = NULL;
742742 }
743743
744− if ((rq->cmd_flags & REQ_DONTPREP) || !q->prep_rq_fn)
744+ if (rq->cmd_flags & REQ_DONTPREP)
745+ break;
746+
747+ if (q->dma_drain_size && rq->data_len) {
748+ /*
749+ * make sure space for the drain appears we
750+ * know we can do this because max_hw_segments
751+ * has been adjusted to be one fewer than the
752+ * device can handle
753+ */
754+ rq->nr_phys_segments++;
755+ rq->nr_hw_segments++;
756+ }
757+
758+ if (!q->prep_rq_fn)
745759 break;
746760
747761 ret = q->prep_rq_fn(q, rq);
@@ -754,6 +768,16 @@ struct request *elv_next_request(struct request_queue *q) · 6 unmodified lines
754768 * avoid resource deadlock. REQ_STARTED will
755769 * prevent other fs requests from passing this one.
756770 */
771+ if (q->dma_drain_size && rq->data_len &&
772+ !(rq->cmd_flags & REQ_DONTPREP)) {
773+ /*
774+ * remove the space for the drain we added
775+ * so that we don't add it again
776+ */
777+ --rq->nr_phys_segments;
778+ --rq->nr_hw_segments;
779+ }
780+
757781 rq = NULL;
758782 break;
759783 } else if (ret == BLKPREP_KILL) {
block/ll_rw_blk.c+49−0
@@ -725,6 +725,45 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b) · 724 unmodified lines
725725
726726 EXPORT_SYMBOL(blk_queue_stack_limits);
727727
728+/**
729+ * blk_queue_dma_drain - Set up a drain buffer for excess dma.
730+ *
731+ * @q: the request queue for the device
732+ * @buf: physically contiguous buffer
733+ * @size: size of the buffer in bytes
734+ *
735+ * Some devices have excess DMA problems and can't simply discard (or
736+ * zero fill) the unwanted piece of the transfer. They have to have a
737+ * real area of memory to transfer it into. The use case for this is
738+ * ATAPI devices in DMA mode. If the packet command causes a transfer
739+ * bigger than the transfer size some HBAs will lock up if there
740+ * aren't DMA elements to contain the excess transfer. What this API
741+ * does is adjust the queue so that the buf is always appended
742+ * silently to the scatterlist.
743+ *
744+ * Note: This routine adjusts max_hw_segments to make room for
745+ * appending the drain buffer. If you call
746+ * blk_queue_max_hw_segments() or blk_queue_max_phys_segments() after
747+ * calling this routine, you must set the limit to one fewer than your
748+ * device can support otherwise there won't be room for the drain
749+ * buffer.
750+ */
751+int blk_queue_dma_drain(struct request_queue *q, void *buf,
752+ unsigned int size)
753+{
754+ if (q->max_hw_segments < 2 || q->max_phys_segments < 2)
755+ return -EINVAL;
756+ /* make room for appending the drain */
757+ --q->max_hw_segments;
758+ --q->max_phys_segments;
759+ q->dma_drain_buffer = buf;
760+ q->dma_drain_size = size;
761+
762+ return 0;
763+}
764+
765+EXPORT_SYMBOL_GPL(blk_queue_dma_drain);
766+
728767 /**
729768 * blk_queue_segment_boundary - set boundary rules for segment merging
730769 * @q: the request queue for the device
@@ -1379,6 +1418,16 @@ new_segment: · 648 unmodified lines
13791418 bvprv = bvec;
13801419 } /* segments in rq */
13811420
1421+ if (q->dma_drain_size) {
1422+ sg->page_link &= ~0x02;
1423+ sg = sg_next(sg);
1424+ sg_set_page(sg, virt_to_page(q->dma_drain_buffer),
1425+ q->dma_drain_size,
1426+ ((unsigned long)q->dma_drain_buffer) &
1427+ (PAGE_SIZE - 1));
1428+ nsegs++;
1429+ }
1430+
13821431 if (sg)
13831432 sg_mark_end(sg);
13841433
include/linux/blkdev.h+4−0
@@ -429,6 +429,8 @@ struct request_queue · 428 unmodified lines
429429 unsigned int max_segment_size;
430430
431431 unsigned long seg_boundary_mask;
432+ void *dma_drain_buffer;
433+ unsigned int dma_drain_size;
432434 unsigned int dma_alignment;
433435
434436 struct blk_queue_tag *queue_tags;
@@ -760,6 +762,8 @@ extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short); · 325 unmodified lines
760762 extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
761763 extern void blk_queue_hardsect_size(struct request_queue *, unsigned short);
762764 extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b);
765+extern int blk_queue_dma_drain(struct request_queue *q, void *buf,
766+ unsigned int size);
763767 extern void blk_queue_segment_boundary(struct request_queue *, unsigned long);
764768 extern void blk_queue_prep_rq(struct request_queue *, prep_rq_fn *pfn);
765769 extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);