📄 scsi_merge.c
字号:
* if it is not OK. * * Lock status: io_request_lock is assumed to be held here. * * Notes: Some drivers have limited scatter-gather table sizes, and * thus they cannot queue an infinitely large command. This * function is called from ll_rw_blk before it attempts to merge * a new block into a request to make sure that the request will * not become too large. * * This function is not designed to be directly called. Instead * it should be referenced from other functions where the * use_clustering and dma_host parameters should be integer * constants. The compiler should thus be able to properly * optimize the code, eliminating stuff that is irrelevant. * It is more maintainable to do this way with a single function * than to have 4 separate functions all doing roughly the * same thing. */__inline static int __scsi_back_merge_fn(request_queue_t * q, struct request *req, struct buffer_head *bh, int max_segments, int use_clustering, int dma_host){ unsigned int count; unsigned int segment_size = 0; Scsi_Device *SDpnt; struct Scsi_Host *SHpnt; SDpnt = (Scsi_Device *) q->queuedata; SHpnt = SDpnt->host; if (max_segments > 64) max_segments = 64; if (use_clustering) { /* * See if we can do this without creating another * scatter-gather segment. In the event that this is a * DMA capable host, make sure that a segment doesn't span * the DMA threshold boundary. */ if (dma_host && virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) { goto new_end_segment; } if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) {#ifdef DMA_SEGMENT_SIZE_LIMITED if( dma_host && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) { segment_size = 0; count = __count_segments(req, use_clustering, dma_host, &segment_size); if( segment_size + bh->b_size > PAGE_SIZE ) { goto new_end_segment; } }#endif /* * This one is OK. Let it go. */ return 1; } } new_end_segment:#ifdef DMA_CHUNK_SIZE if (MERGEABLE_BUFFERS(req->bhtail, bh)) return scsi_new_mergeable(q, req, SHpnt, max_segments);#endif return scsi_new_segment(q, req, SHpnt, max_segments);}__inline static int __scsi_front_merge_fn(request_queue_t * q, struct request *req, struct buffer_head *bh, int max_segments, int use_clustering, int dma_host){ unsigned int count; unsigned int segment_size = 0; Scsi_Device *SDpnt; struct Scsi_Host *SHpnt; SDpnt = (Scsi_Device *) q->queuedata; SHpnt = SDpnt->host; if (max_segments > 64) max_segments = 64; if (use_clustering) { /* * See if we can do this without creating another * scatter-gather segment. In the event that this is a * DMA capable host, make sure that a segment doesn't span * the DMA threshold boundary. */ if (dma_host && virt_to_phys(bh->b_data) - 1 == ISA_DMA_THRESHOLD) { goto new_start_segment; } if (CONTIGUOUS_BUFFERS(bh, req->bh)) {#ifdef DMA_SEGMENT_SIZE_LIMITED if( dma_host && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) { segment_size = bh->b_size; count = __count_segments(req, use_clustering, dma_host, &segment_size); if( count != req->nr_segments ) { goto new_start_segment; } }#endif /* * This one is OK. Let it go. */ return 1; } } new_start_segment:#ifdef DMA_CHUNK_SIZE if (MERGEABLE_BUFFERS(bh, req->bh)) return scsi_new_mergeable(q, req, SHpnt, max_segments);#endif return scsi_new_segment(q, req, SHpnt, max_segments);}/* * Function: scsi_merge_fn_() * * Purpose: queue merge function. * * Arguments: q - Queue for which we are merging request. * req - request into which we wish to merge. * bh - Block which we may wish to merge into request * * Returns: 1 if it is OK to merge the block into the request. 0 * if it is not OK. * * Lock status: io_request_lock is assumed to be held here. * * Notes: Optimized for different cases depending upon whether * ISA DMA is in use and whether clustering should be used. */#define MERGEFCT(_FUNCTION, _BACK_FRONT, _CLUSTER, _DMA) \static int _FUNCTION(request_queue_t * q, \ struct request * req, \ struct buffer_head * bh, \ int max_segments) \{ \ int ret; \ SANITY_CHECK(req, _CLUSTER, _DMA); \ ret = __scsi_ ## _BACK_FRONT ## _merge_fn(q, \ req, \ bh, \ max_segments, \ _CLUSTER, \ _DMA); \ return ret; \}/* Version with use_clustering 0 and dma_host 1 is not necessary, * since the only use of dma_host above is protected by use_clustering. */MERGEFCT(scsi_back_merge_fn_, back, 0, 0)MERGEFCT(scsi_back_merge_fn_c, back, 1, 0)MERGEFCT(scsi_back_merge_fn_dc, back, 1, 1)MERGEFCT(scsi_front_merge_fn_, front, 0, 0)MERGEFCT(scsi_front_merge_fn_c, front, 1, 0)MERGEFCT(scsi_front_merge_fn_dc, front, 1, 1)/* * Function: __scsi_merge_requests_fn() * * Purpose: Prototype for queue merge function. * * Arguments: q - Queue for which we are merging request. * req - request into which we wish to merge. * next - 2nd request that we might want to combine with req * use_clustering - 1 if this host wishes to use clustering * dma_host - 1 if this host has ISA DMA issues (bus doesn't * expose all of the address lines, so that DMA cannot * be done from an arbitrary address). * * Returns: 1 if it is OK to merge the two requests. 0 * if it is not OK. * * Lock status: io_request_lock is assumed to be held here. * * Notes: Some drivers have limited scatter-gather table sizes, and * thus they cannot queue an infinitely large command. This * function is called from ll_rw_blk before it attempts to merge * a new block into a request to make sure that the request will * not become too large. * * This function is not designed to be directly called. Instead * it should be referenced from other functions where the * use_clustering and dma_host parameters should be integer * constants. The compiler should thus be able to properly * optimize the code, eliminating stuff that is irrelevant. * It is more maintainable to do this way with a single function * than to have 4 separate functions all doing roughly the * same thing. */__inline static int __scsi_merge_requests_fn(request_queue_t * q, struct request *req, struct request *next, int max_segments, int use_clustering, int dma_host){ Scsi_Device *SDpnt; struct Scsi_Host *SHpnt; SDpnt = (Scsi_Device *) q->queuedata; SHpnt = SDpnt->host; if (max_segments > 64) max_segments = 64;#ifdef DMA_CHUNK_SIZE /* If it would not fit into prepared memory space for sg chain, * then don't allow the merge. */ if (req->nr_segments + next->nr_segments - 1 > max_segments || req->nr_segments + next->nr_segments - 1 > SHpnt->sg_tablesize) { return 0; } if (req->nr_hw_segments + next->nr_hw_segments - 1 > SHpnt->sg_tablesize) { return 0; }#else /* * If the two requests together are too large (even assuming that we * can merge the boundary requests into one segment, then don't * allow the merge. */ if (req->nr_segments + next->nr_segments - 1 > SHpnt->sg_tablesize) { return 0; }#endif /* * The main question is whether the two segments at the boundaries * would be considered one or two. */ if (use_clustering) { /* * See if we can do this without creating another * scatter-gather segment. In the event that this is a * DMA capable host, make sure that a segment doesn't span * the DMA threshold boundary. */ if (dma_host && virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) { goto dont_combine; }#ifdef DMA_SEGMENT_SIZE_LIMITED /* * We currently can only allocate scatter-gather bounce * buffers in chunks of PAGE_SIZE or less. */ if (dma_host && CONTIGUOUS_BUFFERS(req->bhtail, next->bh) && virt_to_phys(req->bhtail->b_data) - 1 >= ISA_DMA_THRESHOLD ) { int segment_size = 0; int count = 0; count = __count_segments(req, use_clustering, dma_host, &segment_size); count += __count_segments(next, use_clustering, dma_host, &segment_size); if( count != req->nr_segments + next->nr_segments ) { goto dont_combine; } }#endif if (CONTIGUOUS_BUFFERS(req->bhtail, next->bh)) { /* * This one is OK. Let it go. */ req->nr_segments += next->nr_segments - 1; q->elevator.nr_segments--;#ifdef DMA_CHUNK_SIZE req->nr_hw_segments += next->nr_hw_segments - 1;#endif return 1; } } dont_combine:#ifdef DMA_CHUNK_SIZE if (req->nr_segments + next->nr_segments > max_segments || req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) { return 0; } /* If dynamic DMA mapping can merge last segment in req with * first segment in next, then the check for hw segments was * done above already, so we can always merge. */ if (MERGEABLE_BUFFERS (req->bhtail, next->bh)) { req->nr_hw_segments += next->nr_hw_segments - 1; } else if (req->nr_hw_segments + next->nr_hw_segments > SHpnt->sg_tablesize) { return 0; } else { req->nr_hw_segments += next->nr_hw_segments; } req->nr_segments += next->nr_segments; return 1;#else /* * We know that the two requests at the boundary should not be combined. * Make sure we can fix something that is the sum of the two. * A slightly stricter test than we had above. */ if (req->nr_segments + next->nr_segments > max_segments || req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) { return 0; } else { /* * This will form the start of a new segment. Bump the * counter. */ req->nr_segments += next->nr_segments; return 1; }#endif}/* * Function: scsi_merge_requests_fn_() * * Purpose: queue merge function. * * Arguments: q - Queue for which we are merging request. * req - request into which we wish to merge. * bh - Block which we may wish to merge into request * * Returns: 1 if it is OK to merge the block into the request. 0 * if it is not OK. * * Lock status: io_request_lock is assumed to be held here. * * Notes: Optimized for different cases depending upon whether * ISA DMA is in use and whether clustering should be used. */#define MERGEREQFCT(_FUNCTION, _CLUSTER, _DMA) \static int _FUNCTION(request_queue_t * q, \ struct request * req, \ struct request * next, \ int max_segments) \{ \ int ret; \ SANITY_CHECK(req, _CLUSTER, _DMA); \ ret = __scsi_merge_requests_fn(q, req, next, max_segments, _CLUSTER, _DMA); \ return ret; \}/* Version with use_clustering 0 and dma_host 1 is not necessary, * since the only use of dma_host above is protected by use_clustering. */MERGEREQFCT(scsi_merge_requests_fn_, 0, 0)MERGEREQFCT(scsi_merge_requests_fn_c, 1, 0)MERGEREQFCT(scsi_merge_requests_fn_dc, 1, 1)/* * Function: __init_io() * * Purpose: Prototype for io initialize function. * * Arguments: SCpnt - Command descriptor we wish to initialize * sg_count_valid - 1 if the sg count in the req is valid. * use_clustering - 1 if this host wishes to use clustering * dma_host - 1 if this host has ISA DMA issues (bus doesn't * expose all of the address lines, so that DMA cannot * be done from an arbitrary address). * * Returns: 1 on success. * * Lock status: * * Notes: Only the SCpnt argument should be a non-constant variable. * This function is designed in such a way that it will be * invoked from a series of small stubs, each of which would * be optimized for specific circumstances. * * The advantage of this is that hosts that don't do DMA * get versions of the function that essentially don't have
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -