Calmed down SCSI bus manager a bit in case it got a non-DMA safe buffer

from block_io (which seem to happen frequently...).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13948 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-08-13 12:39:10 +00:00
parent b96ea69c37
commit 944eada15a
@@ -29,7 +29,8 @@
#include <string.h> #include <string.h>
// check whether S/G list of request is supported DMA controller /** check whether S/G list of request is supported DMA controller */
static bool static bool
is_sg_list_dma_safe(scsi_ccb *request) is_sg_list_dma_safe(scsi_ccb *request)
{ {
@@ -43,7 +44,7 @@ is_sg_list_dma_safe(scsi_ccb *request)
// not too many S/G list entries // not too many S/G list entries
if (sg_count > bus->dma_params.max_sg_blocks) { if (sg_count > bus->dma_params.max_sg_blocks) {
SHOW_FLOW0( 0, "S/G-list too long" ); SHOW_FLOW0(1, "S/G-list too long");
return false; return false;
} }
@@ -101,7 +102,7 @@ scsi_copy_dma_buffer(scsi_ccb *request, uint32 size, bool to_buffer)
uint32 num_vecs = buffer->sg_cnt_orig; uint32 num_vecs = buffer->sg_cnt_orig;
char *buffer_data = buffer->address; char *buffer_data = buffer->address;
SHOW_FLOW(0, "to_buffer=%d, %d bytes", to_buffer, (int)size); SHOW_FLOW(1, "to_buffer=%d, %d bytes", to_buffer, (int)size);
// survive even if controller returned invalid data size // survive even if controller returned invalid data size
size = min(size, request->data_len); size = min(size, request->data_len);
@@ -132,22 +133,25 @@ scsi_copy_dma_buffer(scsi_ccb *request, uint32 size, bool to_buffer)
} }
// get log2 static int
static int log2( uint32 x ) log2(uint32 x)
{ {
int y; int y;
for( y = 31; y >= 0; --y ) for (y = 31; y >= 0; --y) {
if (x == ((uint32)1 << y)) if (x == ((uint32)1 << y))
break; break;
}
return y; return y;
} }
static void scsi_free_dma_buffer( dma_buffer *buffer )
static void
scsi_free_dma_buffer(dma_buffer *buffer)
{ {
if (buffer->area > 0) { if (buffer->area > 0) {
SHOW_FLOW0( 0, "Destroying buffer" ); SHOW_FLOW0(1, "Destroying buffer");
delete_area(buffer->area); delete_area(buffer->area);
buffer->area = 0; buffer->area = 0;
@@ -180,17 +184,15 @@ scsi_alloc_dma_buffer(dma_buffer *buffer, dma_params *dma_params, uint32 size)
// calculate worst case number of S/G entries, i.e. if they are non-continuous; // calculate worst case number of S/G entries, i.e. if they are non-continuous;
// there is a controller limit and a limit by our own S/G manager to check // there is a controller limit and a limit by our own S/G manager to check
if( size / B_PAGE_SIZE > dma_params->max_sg_blocks || if (size / B_PAGE_SIZE > dma_params->max_sg_blocks
size / B_PAGE_SIZE > MAX_TEMP_SG_FRAGMENTS ) || size / B_PAGE_SIZE > MAX_TEMP_SG_FRAGMENTS) {
{
uint32 boundary = dma_params->dma_boundary; uint32 boundary = dma_params->dma_boundary;
uchar *dma_buffer_address_unaligned; uchar *dma_buffer_address_unaligned;
// alright - a contiguous buffer is required to keep S/G table short // alright - a contiguous buffer is required to keep S/G table short
SHOW_INFO( 0, "need to setup contiguous DMA buffer of size %d", SHOW_INFO(1, "need to setup contiguous DMA buffer of size %d",
(int)size); (int)size);
// verify that we don't get problems with dma boundary // verify that we don't get problems with dma boundary
if (boundary != ~0UL) { if (boundary != ~0UL) {
if (size > boundary + 1) { if (size > boundary + 1) {
@@ -294,7 +296,9 @@ scsi_alloc_dma_buffer(dma_buffer *buffer, dma_params *dma_params, uint32 size)
return true; return true;
} }
static void scsi_free_dma_buffer_sg_orig( dma_buffer *buffer )
static void
scsi_free_dma_buffer_sg_orig(dma_buffer *buffer)
{ {
if (buffer->sg_orig > 0) { if (buffer->sg_orig > 0) {
delete_area(buffer->sg_orig); delete_area(buffer->sg_orig);
@@ -304,8 +308,10 @@ static void scsi_free_dma_buffer_sg_orig( dma_buffer *buffer )
} }
// allocate S/G list to original data /** allocate S/G list to original data */
static bool scsi_alloc_dma_buffer_sg_orig( dma_buffer *buffer, int size )
static bool
scsi_alloc_dma_buffer_sg_orig(dma_buffer *buffer, int size)
{ {
// free old list first // free old list first
scsi_free_dma_buffer_sg_orig(buffer); scsi_free_dma_buffer_sg_orig(buffer);
@@ -331,23 +337,27 @@ static bool scsi_alloc_dma_buffer_sg_orig( dma_buffer *buffer, int size )
} }
// helper: dump S/G table /** helper: dump S/G table */
static void dump_sg_table( const physical_entry *sg_list,
static void
dump_sg_table(const physical_entry *sg_list,
uint32 sg_list_count) uint32 sg_list_count)
{ {
uint32 cur_idx; uint32 cur_idx;
SHOW_FLOW( 0, "count=%d", (int)sg_list_count ); SHOW_FLOW(1, "count=%d", (int)sg_list_count);
for (cur_idx = sg_list_count; cur_idx >= 1; --cur_idx, ++sg_list) { for (cur_idx = sg_list_count; cur_idx >= 1; --cur_idx, ++sg_list) {
SHOW_FLOW( 0, "addr=%x, size=%d", (int)sg_list->address, SHOW_FLOW(1, "addr=%x, size=%d", (int)sg_list->address,
(int)sg_list->size); (int)sg_list->size);
} }
} }
// compose S/G list to original data of request /** compose S/G list to original data of request */
static bool scsi_dma_buffer_compose_sg_orig( dma_buffer *buffer, scsi_ccb *request )
static bool
scsi_dma_buffer_compose_sg_orig(dma_buffer *buffer, scsi_ccb *request)
{ {
// enlarge buffer is required // enlarge buffer is required
if (buffer->sg_cnt_max_orig < request->sg_cnt) { if (buffer->sg_cnt_max_orig < request->sg_cnt) {
@@ -355,7 +365,7 @@ static bool scsi_dma_buffer_compose_sg_orig( dma_buffer *buffer, scsi_ccb *reque
return false; return false;
} }
SHOW_FLOW0( 0, "copy S/G list" ); SHOW_FLOW0(1, "copy S/G list");
memcpy(buffer->sg_list_orig, request->sg_list, memcpy(buffer->sg_list_orig, request->sg_list,
request->sg_cnt * sizeof(physical_entry)); request->sg_cnt * sizeof(physical_entry));
@@ -365,9 +375,12 @@ static bool scsi_dma_buffer_compose_sg_orig( dma_buffer *buffer, scsi_ccb *reque
} }
// init DMA buffer and copy data to it if required /** init DMA buffer and copy data to it if required
// note: S/G list of request must already be setup * note: S/G list of request must already be setup
bool scsi_get_dma_buffer( scsi_ccb *request ) */
bool
scsi_get_dma_buffer(scsi_ccb *request)
{ {
scsi_device_info *device = request->device; scsi_device_info *device = request->device;
dma_buffer *buffer; dma_buffer *buffer;
@@ -378,7 +391,7 @@ bool scsi_get_dma_buffer( scsi_ccb *request )
if( is_sg_list_dma_safe( request )) if( is_sg_list_dma_safe( request ))
return true; return true;
SHOW_FLOW0( 0, "Buffer is not DMA safe" ); SHOW_FLOW0(1, "Buffer is not DMA safe" );
dump_sg_table(request->sg_list, request->sg_cnt); dump_sg_table(request->sg_list, request->sg_cnt);
@@ -402,10 +415,8 @@ bool scsi_get_dma_buffer( scsi_ccb *request )
if (buffer->size < request->data_len) { if (buffer->size < request->data_len) {
if (!scsi_alloc_dma_buffer(buffer, &device->bus->dma_params, if (!scsi_alloc_dma_buffer(buffer, &device->bus->dma_params,
request->data_len)) request->data_len))
{
goto err; goto err;
} }
}
// create S/G to original data (necessary for copying from-buffer on end // create S/G to original data (necessary for copying from-buffer on end
// of request, but also used during copying to-buffer in a second because // of request, but also used during copying to-buffer in a second because
@@ -427,8 +438,7 @@ bool scsi_get_dma_buffer( scsi_ccb *request )
request->sg_list = buffer->sg_list; request->sg_list = buffer->sg_list;
request->sg_cnt = buffer->sg_cnt; request->sg_cnt = buffer->sg_cnt;
SHOW_INFO( 0, "bytes: %d", (int)request->data_len ); SHOW_INFO(1, "bytes: %d", (int)request->data_len);
SHOW_INFO0(3, "we can start now"); SHOW_INFO0(3, "we can start now");
request->buffered = true; request->buffered = true;
@@ -449,20 +459,23 @@ err:
} }
// copy data back and release DMA buffer; /** copy data back and release DMA buffer;
// you must have called cleanup_tmp_sg before * you must have called cleanup_tmp_sg before
void scsi_release_dma_buffer( scsi_ccb *request ) */
void
scsi_release_dma_buffer(scsi_ccb *request)
{ {
scsi_device_info *device = request->device; scsi_device_info *device = request->device;
dma_buffer *buffer = request->dma_buffer; dma_buffer *buffer = request->dma_buffer;
SHOW_FLOW( 0, "Buffering finished, %x, %x", SHOW_FLOW(1, "Buffering finished, %x, %x",
request->subsys_status & SCSI_SUBSYS_STATUS_MASK, request->subsys_status & SCSI_SUBSYS_STATUS_MASK,
(int)(request->flags & SCSI_DIR_MASK)); (int)(request->flags & SCSI_DIR_MASK));
// copy data from buffer if required and if operation succeeded // copy data from buffer if required and if operation succeeded
if( (request->subsys_status & SCSI_SUBSYS_STATUS_MASK) == SCSI_REQ_CMP && if ((request->subsys_status & SCSI_SUBSYS_STATUS_MASK) == SCSI_REQ_CMP
(request->flags & SCSI_DIR_MASK) == SCSI_DIR_IN ) && (request->flags & SCSI_DIR_MASK) == SCSI_DIR_IN)
scsi_copy_dma_buffer(request, request->data_len - request->data_resid, false ); scsi_copy_dma_buffer(request, request->data_len - request->data_resid, false );
// restore request // restore request
@@ -484,8 +497,10 @@ void scsi_release_dma_buffer( scsi_ccb *request )
} }
// dameon that deletes DMA buffer if not used for some time /** dameon that deletes DMA buffer if not used for some time */
void scsi_dma_buffer_daemon( void *dev, int counter )
void
scsi_dma_buffer_daemon(void *dev, int counter)
{ {
scsi_device_info *device = dev; scsi_device_info *device = dev;
dma_buffer *buffer; dma_buffer *buffer;
@@ -494,9 +509,8 @@ void scsi_dma_buffer_daemon( void *dev, int counter )
buffer = &device->dma_buffer; buffer = &device->dma_buffer;
if( !buffer->inuse && if (!buffer->inuse
buffer->last_use - system_time() > SCSI_DMA_BUFFER_CLEANUP_DELAY ) && buffer->last_use - system_time() > SCSI_DMA_BUFFER_CLEANUP_DELAY) {
{
scsi_free_dma_buffer(buffer); scsi_free_dma_buffer(buffer);
scsi_free_dma_buffer_sg_orig(buffer); scsi_free_dma_buffer_sg_orig(buffer);
} }
@@ -504,13 +518,17 @@ void scsi_dma_buffer_daemon( void *dev, int counter )
RELEASE_BEN(&device->dma_buffer_lock); RELEASE_BEN(&device->dma_buffer_lock);
} }
void scsi_dma_buffer_free( dma_buffer *buffer )
void
scsi_dma_buffer_free(dma_buffer *buffer)
{ {
scsi_free_dma_buffer(buffer); scsi_free_dma_buffer(buffer);
scsi_free_dma_buffer_sg_orig(buffer); scsi_free_dma_buffer_sg_orig(buffer);
} }
void scsi_dma_buffer_init( dma_buffer *buffer )
void
scsi_dma_buffer_init(dma_buffer *buffer)
{ {
buffer->area = 0; buffer->area = 0;
buffer->size = 0; buffer->size = 0;