SCSI: Respect DMA_HIGH_ADDRESS, if specified.
Related to #19191 and others.
This commit is contained in:
@@ -217,6 +217,9 @@ scsi_init_bus(device_node *node, void **cookie)
|
|||||||
if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_COUNT,
|
if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_COUNT,
|
||||||
&bus->dma_params.max_sg_blocks, true) != B_OK)
|
&bus->dma_params.max_sg_blocks, true) != B_OK)
|
||||||
bus->dma_params.max_sg_blocks = ~0;
|
bus->dma_params.max_sg_blocks = ~0;
|
||||||
|
if (pnp->get_attr_uint64(node, B_DMA_HIGH_ADDRESS,
|
||||||
|
&bus->dma_params.high_address, true) != B_OK)
|
||||||
|
bus->dma_params.high_address = ~0;
|
||||||
|
|
||||||
// do some sanity check:
|
// do some sanity check:
|
||||||
bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment;
|
bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment;
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ is_sg_list_dma_safe(scsi_ccb *request)
|
|||||||
scsi_bus_info *bus = request->bus;
|
scsi_bus_info *bus = request->bus;
|
||||||
const physical_entry *sg_list = request->sg_list;
|
const physical_entry *sg_list = request->sg_list;
|
||||||
uint32 sg_count = request->sg_count;
|
uint32 sg_count = request->sg_count;
|
||||||
uint32 dma_boundary = bus->dma_params.dma_boundary;
|
const uint32 dma_boundary = bus->dma_params.dma_boundary;
|
||||||
uint32 alignment = bus->dma_params.alignment;
|
const uint32 alignment = bus->dma_params.alignment;
|
||||||
uint32 max_sg_block_size = bus->dma_params.max_sg_block_size;
|
const uint32 max_sg_block_size = bus->dma_params.max_sg_block_size;
|
||||||
uint32 cur_idx;
|
const uint64 high_address = bus->dma_params.high_address;
|
||||||
|
|
||||||
// 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) {
|
||||||
@@ -54,8 +54,8 @@ is_sg_list_dma_safe(scsi_ccb *request)
|
|||||||
if (dma_boundary == ~(uint32)0 && alignment == 0 && max_sg_block_size == 0)
|
if (dma_boundary == ~(uint32)0 && alignment == 0 && max_sg_block_size == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// argh - controller is a bit picky, so make sure he likes us
|
// argh - controller is a bit picky, so make sure it likes us
|
||||||
for (cur_idx = sg_count; cur_idx >= 1; --cur_idx, ++sg_list) {
|
for (uint32 cur_idx = sg_count; cur_idx >= 1; --cur_idx, ++sg_list) {
|
||||||
phys_addr_t max_len;
|
phys_addr_t max_len;
|
||||||
|
|
||||||
// calculate space upto next dma boundary crossing and
|
// calculate space upto next dma boundary crossing and
|
||||||
@@ -81,6 +81,12 @@ is_sg_list_dma_safe(scsi_ccb *request)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((sg_list->address + sg_list->size) > high_address) {
|
||||||
|
SHOW_FLOW(0, "S/G-entry above high address @%" B_PRIxPHYSADDR,
|
||||||
|
sg_list->address + sg_list->size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// verify entry size
|
// verify entry size
|
||||||
if (sg_list->size > max_sg_block_size) {
|
if (sg_list->size > max_sg_block_size) {
|
||||||
SHOW_FLOW(0, "S/G-entry is too long (%" B_PRIuPHYSADDR "/%" B_PRIu32
|
SHOW_FLOW(0, "S/G-entry is too long (%" B_PRIuPHYSADDR "/%" B_PRIu32
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ typedef struct dma_params {
|
|||||||
uint32 dma_boundary;
|
uint32 dma_boundary;
|
||||||
uint32 max_sg_block_size;
|
uint32 max_sg_block_size;
|
||||||
uint32 max_sg_blocks;
|
uint32 max_sg_blocks;
|
||||||
|
uint64 high_address;
|
||||||
} dma_params;
|
} dma_params;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user