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:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user