SCSI: Respect DMA_HIGH_ADDRESS, if specified.

Related to #19191 and others.
This commit is contained in:
Augustin Cavalier 2024-10-22 11:23:59 -04:00
parent b88d29aa2c
commit 1b05bf1a7e
3 changed files with 16 additions and 6 deletions

View File

@ -217,6 +217,9 @@ scsi_init_bus(device_node *node, void **cookie)
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 = ~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:
bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment;

View File

@ -39,10 +39,10 @@ is_sg_list_dma_safe(scsi_ccb *request)
scsi_bus_info *bus = request->bus;
const physical_entry *sg_list = request->sg_list;
uint32 sg_count = request->sg_count;
uint32 dma_boundary = bus->dma_params.dma_boundary;
uint32 alignment = bus->dma_params.alignment;
uint32 max_sg_block_size = bus->dma_params.max_sg_block_size;
uint32 cur_idx;
const uint32 dma_boundary = bus->dma_params.dma_boundary;
const uint32 alignment = bus->dma_params.alignment;
const uint32 max_sg_block_size = bus->dma_params.max_sg_block_size;
const uint64 high_address = bus->dma_params.high_address;
// not too many S/G list entries
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)
return true;
// argh - controller is a bit picky, so make sure he likes us
for (cur_idx = sg_count; cur_idx >= 1; --cur_idx, ++sg_list) {
// argh - controller is a bit picky, so make sure it likes us
for (uint32 cur_idx = sg_count; cur_idx >= 1; --cur_idx, ++sg_list) {
phys_addr_t max_len;
// calculate space upto next dma boundary crossing and
@ -81,6 +81,12 @@ is_sg_list_dma_safe(scsi_ccb *request)
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
if (sg_list->size > max_sg_block_size) {
SHOW_FLOW(0, "S/G-entry is too long (%" B_PRIuPHYSADDR "/%" B_PRIu32

View File

@ -79,6 +79,7 @@ typedef struct dma_params {
uint32 dma_boundary;
uint32 max_sg_block_size;
uint32 max_sg_blocks;
uint64 high_address;
} dma_params;