* Replaced the B_BLOCK_DEVICE_* defines with B_DMA_* defines that better match
our dma_restrictions structure (but we're using blocks instead of bytes, since unlike the block size, the restrictions attributes are constant). * We might want to use blocks for the dma_restrictions structure as well in the future... * Fixed another bug in the device_node variant of DMAResource::Init(): the max segment size was specified in blocks as well. * Removed the "hardcode" block_io module and header. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26973 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef __BLOCK_IO_H__
|
||||
#define __BLOCK_IO_H__
|
||||
|
||||
/*!
|
||||
Block devices can be easily written by providing the interface
|
||||
specified hereinafter. The block device manager takes care of
|
||||
DMA and other restrictions imposed by underlying controller or
|
||||
protocol and transparently handles transmission of partial blocks
|
||||
by using a buffer (performance will suffer, though).
|
||||
*/
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <device_manager.h>
|
||||
|
||||
// cookies issued by block_io
|
||||
typedef struct block_io_device_info *block_io_device;
|
||||
typedef struct block_io_handle_info *block_io_handle;
|
||||
|
||||
// cookies issued by device driver
|
||||
typedef struct block_device_handle_cookie block_device_handle_cookie;
|
||||
|
||||
|
||||
// two reason why to use array of size 1:
|
||||
// 1. zero-sized arrays aren't standard C
|
||||
// 2. it's handy if you need a temporary global variable with num=1
|
||||
typedef struct phys_vecs {
|
||||
size_t num;
|
||||
size_t total_len;
|
||||
physical_entry vec[1];
|
||||
} phys_vecs;
|
||||
|
||||
#define PHYS_VECS(name, size) \
|
||||
uint8 name[sizeof(phys_vecs) + (size - 1)*sizeof(phys_vec)]; \
|
||||
phys_vecs *name = (phys_vecs *)name
|
||||
|
||||
|
||||
// Block Device Node
|
||||
|
||||
// attributes:
|
||||
|
||||
// if true, this device may be a BIOS drive (uint8, optional, default: false)
|
||||
#define B_BLOCK_DEVICE_IS_BIOS_DRIVE "block_device/is_bios_drive"
|
||||
// address bits that must be 0 - must be 2^i-1 for some i (uint32, optional, default: 0)
|
||||
#define B_BLOCK_DEVICE_DMA_ALIGNMENT "block_device/dma_alignment"
|
||||
// maximum number of blocks per transfer (uint32, optional, default: unlimited)
|
||||
#define B_BLOCK_DEVICE_MAX_BLOCKS_ITEM "block_device/max_blocks"
|
||||
// mask of bits that can change in one sg block (uint32, optional, default: ~0)
|
||||
#define B_BLOCK_DEVICE_DMA_BOUNDARY "block_device/dma_boundary"
|
||||
// maximum size of one block in scatter/gather list (uint32, optional, default: ~0)
|
||||
#define B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE "block_device/max_sg_block_size"
|
||||
// maximum number of scatter/gather blocks (uint32, optional, default: unlimited)
|
||||
#define B_BLOCK_DEVICE_MAX_SG_BLOCKS "block_device/max_sg_blocks"
|
||||
|
||||
typedef struct block_device_cookie {
|
||||
device_node *node;
|
||||
} block_device_cookie;
|
||||
|
||||
// interface to be provided by device driver
|
||||
typedef struct block_device_interface {
|
||||
driver_module_info info;
|
||||
|
||||
void (*set_device)(block_device_cookie *cookie, block_io_device device);
|
||||
|
||||
// iovecs are physical address here
|
||||
// pos and num_blocks are in blocks; bytes_transferred in bytes
|
||||
// vecs are guaranteed to describe enough data for given block count
|
||||
status_t (*open)(block_device_cookie *cookie, block_device_handle_cookie **handle);
|
||||
status_t (*close)(block_device_handle_cookie *handle);
|
||||
status_t (*free)(block_device_handle_cookie *handle);
|
||||
|
||||
status_t (*read)(block_device_handle_cookie *handle, const phys_vecs *vecs, off_t pos,
|
||||
size_t num_blocks, uint32 block_size, size_t *bytes_transferred);
|
||||
status_t (*write)(block_device_handle_cookie *handle, const phys_vecs *vecs, off_t pos,
|
||||
size_t num_blocks, uint32 block_size, size_t *bytes_transferred);
|
||||
|
||||
status_t (*ioctl)(block_device_handle_cookie *handle, int op, void *buf, size_t len);
|
||||
} block_device_interface;
|
||||
|
||||
#define B_BLOCK_IO_DEVICE_MODULE_NAME "generic/block_io/device_v1"
|
||||
|
||||
|
||||
// Interface for Drivers
|
||||
|
||||
// interface used for callbacks done by driver
|
||||
typedef struct block_io_for_driver_interface {
|
||||
module_info info;
|
||||
|
||||
// block_size - block size in bytes
|
||||
// ld_block_size - log2( block_size) (set to zero if block_size is not power of two)
|
||||
// capacity - capacity in blocks
|
||||
void (*set_media_params)(block_io_device device, uint32 block_size, uint32 ld_block_size,
|
||||
uint64 capacity);
|
||||
} block_io_for_driver_interface;
|
||||
|
||||
#define B_BLOCK_IO_FOR_DRIVER_MODULE_NAME "generic/block_io/driver/v1"
|
||||
|
||||
#endif /* __BLOCK_IO_H__ */
|
||||
@@ -150,6 +150,14 @@ struct driver_module_info {
|
||||
#define B_FIND_MULTIPLE_CHILDREN 0x02
|
||||
#define B_KEEP_DRIVER_LOADED 0x04
|
||||
|
||||
/* DMA attributes */
|
||||
#define B_DMA_LOW_ADDRESS "dma/low_address"
|
||||
#define B_DMA_HIGH_ADDRESS "dma/high_address"
|
||||
#define B_DMA_ALIGNMENT "dma/alignment"
|
||||
#define B_DMA_BOUNDARY "dma/boundary"
|
||||
#define B_DMA_MAX_TRANSFER_BLOCKS "dma/max_transfer_blocks"
|
||||
#define B_DMA_MAX_SEGMENT_BLOCKS "dma/max_segment_blocks"
|
||||
#define B_DMA_MAX_SEGMENT_COUNT "dma/max_segment_count"
|
||||
|
||||
/* interface of device */
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007, Haiku, Inc. All RightsReserved.
|
||||
* Copyright 2004-2008, Haiku, Inc. All RightsReserved.
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
|
||||
#include <bus/SCSI.h>
|
||||
#include <block_io.h>
|
||||
#include <scsi_cmds.h>
|
||||
#include <Drivers.h>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ SubInclude HAIKU_TOP src add-ons kernel bus_managers acpi ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers agp_gart ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers config_manager ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers firewire ;
|
||||
#SubInclude HAIKU_TOP src add-ons kernel bus_managers ata ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers ide ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers isa ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers pci ;
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <block_io.h>
|
||||
|
||||
#define TRACE dprintf
|
||||
|
||||
|
||||
@@ -30,7 +28,7 @@ ide_channel_added(device_node *parent)
|
||||
|
||||
TRACE("ide_channel_added, parent is %p\n", parent);
|
||||
|
||||
if (pnp->get_attr_string(parent, IDE_CONTROLLER_CONTROLLER_NAME_ITEM,
|
||||
if (pnp->get_attr_string(parent, IDE_CONTROLLER_CONTROLLER_NAME_ITEM,
|
||||
&controller_name, true) != B_OK) {
|
||||
dprintf("ide: ignored controller - controller name missing\n");
|
||||
goto err;
|
||||
@@ -61,7 +59,7 @@ ide_channel_added(device_node *parent)
|
||||
// which should be sufficient)
|
||||
// Note: to fix specific drive bugs, use ide_sim_get_restrictions()
|
||||
// in ide_sim.c!
|
||||
{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: 255 }},
|
||||
{ B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { ui32: 255 }},
|
||||
{ IDE_CHANNEL_ID_ITEM, B_UINT32_TYPE, { ui32: channel_id }},
|
||||
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: IDE_CHANNEL_ID_GENERATOR }},
|
||||
// { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: channel_id }},
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <block_io.h>
|
||||
|
||||
|
||||
/** called when an IDE channel was registered by a controller driver */
|
||||
|
||||
@@ -62,7 +60,7 @@ ide_channel_added(device_node *parent)
|
||||
// which should be sufficient)
|
||||
// Note: to fix specific drive bugs, use ide_sim_get_restrictions()
|
||||
// in ide_sim.c!
|
||||
{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: 255 }},
|
||||
{ B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { ui32: 255 }},
|
||||
{ IDE_CHANNEL_ID_ITEM, B_UINT32_TYPE, { ui32: channel_id }},
|
||||
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: IDE_CHANNEL_ID_GENERATOR }},
|
||||
// { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: channel_id }},
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <block_io.h>
|
||||
|
||||
|
||||
// bus service should hurry up a bit - good controllers don't take much time
|
||||
@@ -198,19 +197,23 @@ scsi_init_bus(device_node *node, void **cookie)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// extract controller/protocoll restrictions from node
|
||||
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_DMA_ALIGNMENT, &bus->dma_params.alignment, true) != B_OK)
|
||||
if (pnp->get_attr_uint32(node, B_DMA_ALIGNMENT, &bus->dma_params.alignment,
|
||||
true) != B_OK)
|
||||
bus->dma_params.alignment = 0;
|
||||
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &bus->dma_params.max_blocks, true) != B_OK)
|
||||
if (pnp->get_attr_uint32(node, B_DMA_MAX_TRANSFER_BLOCKS,
|
||||
&bus->dma_params.max_blocks, true) != B_OK)
|
||||
bus->dma_params.max_blocks = 0xffffffff;
|
||||
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_DMA_BOUNDARY, &bus->dma_params.dma_boundary, true) != B_OK)
|
||||
if (pnp->get_attr_uint32(node, B_DMA_BOUNDARY,
|
||||
&bus->dma_params.dma_boundary, true) != B_OK)
|
||||
bus->dma_params.dma_boundary = ~0;
|
||||
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, &bus->dma_params.max_sg_block_size, true) != B_OK)
|
||||
if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_BLOCKS,
|
||||
&bus->dma_params.max_sg_block_size, true) != B_OK)
|
||||
bus->dma_params.max_sg_block_size = 0xffffffff;
|
||||
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_SG_BLOCKS, &bus->dma_params.max_sg_blocks, true) != B_OK)
|
||||
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;
|
||||
|
||||
// do some sanity check:
|
||||
// (see blkman.c)
|
||||
bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment;
|
||||
|
||||
if (bus->dma_params.alignment > B_PAGE_SIZE) {
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
|
||||
#include "scsi_internal.h"
|
||||
|
||||
#include <block_io.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -103,7 +101,8 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
|
||||
// find maximum transfer blocks
|
||||
// set default value to max (need something like ULONG_MAX here)
|
||||
orig_max_blocks = ~0;
|
||||
pnp->get_attr_uint32(bus->node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &orig_max_blocks, true);
|
||||
pnp->get_attr_uint32(bus->node, B_DMA_MAX_TRANSFER_BLOCKS, &orig_max_blocks,
|
||||
true);
|
||||
|
||||
max_blocks = min(max_blocks, orig_max_blocks);
|
||||
|
||||
@@ -130,7 +129,7 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
|
||||
{ B_DEVICE_BUS, B_STRING_TYPE, { string: "scsi" }},
|
||||
|
||||
// extra restriction of maximum number of blocks per transfer
|
||||
{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: max_blocks }},
|
||||
{ B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { ui32: max_blocks }},
|
||||
|
||||
// atapi emulation
|
||||
{ SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }},
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <bus/IDE.h>
|
||||
#include <ide_types.h>
|
||||
#include <device_manager.h>
|
||||
#include <block_io.h>
|
||||
|
||||
|
||||
//#define TRACE_IDE_ISA
|
||||
@@ -78,7 +77,7 @@ publish_channel(device_node *parent, uint16 command_block_base,
|
||||
// DMA properties; the 16 bit alignment is not necessary as
|
||||
// the ide bus manager handles that very efficiently, but why
|
||||
// not use the block device manager for doing that?
|
||||
{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1 }},
|
||||
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1 }},
|
||||
|
||||
// private data to identify device
|
||||
{ IDE_ISA_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }},
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <device_manager.h>
|
||||
#include <bus/IDE.h>
|
||||
#include <ide_adapter.h>
|
||||
#include <block_io.h>
|
||||
|
||||
|
||||
#define DRIVER_PRETTY_NAME "Legacy SATA"
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <bus/ide/ide_adapter.h>
|
||||
#include <block_io.h>
|
||||
|
||||
#define debug_level_flow 0
|
||||
#define debug_level_error 3
|
||||
@@ -95,7 +94,7 @@ inthand(void *arg)
|
||||
if (channel->dmaing) {
|
||||
// in DMA mode, there is a safe test
|
||||
// in PIO mode, this doesn't work
|
||||
*(uint8 *)&bm_status = pci->read_io_8( device,
|
||||
*(uint8 *)&bm_status = pci->read_io_8( device,
|
||||
channel->bus_master_base + ide_bm_status_reg );
|
||||
|
||||
if (!bm_status.interrupt)
|
||||
@@ -179,7 +178,7 @@ controller_removed(device_node_handle node, ide_adapter_controller_info *control
|
||||
// publish node of ide controller
|
||||
|
||||
static status_t
|
||||
publish_controller(device_node_handle parent, uint16 bus_master_base, uint8 intnum,
|
||||
publish_controller(device_node_handle parent, uint16 bus_master_base, uint8 intnum,
|
||||
io_resource_handle *resources, device_node_handle *node)
|
||||
{
|
||||
device_attr attrs[] = {
|
||||
@@ -199,13 +198,13 @@ publish_controller(device_node_handle parent, uint16 bus_master_base, uint8 intn
|
||||
// DMA properties
|
||||
// some say it must be dword-aligned, others that it can be byte-aligned;
|
||||
// stay on the safe side
|
||||
{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 3 }},
|
||||
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 3 }},
|
||||
// one S/G block must not cross 64K boundary
|
||||
{ B_BLOCK_DEVICE_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
|
||||
{ B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
|
||||
// size of S/G block is 16 bits with zero being 64K
|
||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE, { ui32: 0x10000 }},
|
||||
// see definition of MAX_SG_COUNT
|
||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE, { ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
||||
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { ui32: 0x10000 }},
|
||||
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
||||
{ ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
||||
|
||||
// private data to find controller
|
||||
{ IDE_ADAPTER_BUS_MASTER_BASE, B_UINT16_TYPE, { ui16: bus_master_base }},
|
||||
@@ -249,7 +248,7 @@ detect_controller(pci_device_module_info *pci, pci_device pci_device,
|
||||
return publish_controller(parent, bus_master_base, intnum, resource_handles, node);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static status_t
|
||||
probe_controller(device_node_handle parent)
|
||||
{
|
||||
@@ -284,14 +283,14 @@ probe_controller(device_node_handle parent)
|
||||
if (res != B_OK || controller_node == NULL)
|
||||
goto err;
|
||||
|
||||
ide_adapter->detect_channel(pci, device, controller_node,
|
||||
ide_adapter->detect_channel(pci, device, controller_node,
|
||||
PROMISE_TX2_CHANNEL_MODULE_NAME, true,
|
||||
command_block_base[0], control_block_base[0], bus_master_base, intnum,
|
||||
0, "Primary Channel", &channels[0], false);
|
||||
|
||||
ide_adapter->detect_channel(pci, device, controller_node,
|
||||
PROMISE_TX2_CHANNEL_MODULE_NAME, true,
|
||||
command_block_base[1], control_block_base[1], bus_master_base, intnum,
|
||||
ide_adapter->detect_channel(pci, device, controller_node,
|
||||
PROMISE_TX2_CHANNEL_MODULE_NAME, true,
|
||||
command_block_base[1], control_block_base[1], bus_master_base, intnum,
|
||||
1, "Secondary Channel", &channels[1], false);
|
||||
|
||||
pnp->uninit_driver(parent);
|
||||
@@ -299,7 +298,7 @@ probe_controller(device_node_handle parent)
|
||||
return B_OK;
|
||||
|
||||
err:
|
||||
pnp->uninit_driver(parent);
|
||||
pnp->uninit_driver(parent);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <bus/IDE.h>
|
||||
|
||||
#include <ide_adapter.h>
|
||||
#include <block_io.h>
|
||||
|
||||
#define TRACE(x...) dprintf("si-3112: " x)
|
||||
//#define FLOW(x...) dprintf("si-3112: " x)
|
||||
@@ -225,13 +224,13 @@ controller_probe(device_node *parent)
|
||||
// DMA properties
|
||||
// data must be word-aligned;
|
||||
// warning: some controllers are more picky!
|
||||
{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1}},
|
||||
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1}},
|
||||
// one S/G block must not cross 64K boundary
|
||||
{ B_BLOCK_DEVICE_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
|
||||
{ B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
|
||||
// max size of S/G block is 16 bits with zero being 64K
|
||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE, { ui32: 0x10000 }},
|
||||
// see definition of MAX_SG_COUNT
|
||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE, { ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
||||
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { ui32: 0x10000 }},
|
||||
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
||||
{ ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
||||
|
||||
// private data to find controller
|
||||
{ "silicon_image_3112/asic_index", B_UINT32_TYPE, { ui32: asicIndex }},
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <block_io.h>
|
||||
|
||||
|
||||
#define TRACE(a...) dprintf("\33[35mahci:\33[0m " a)
|
||||
#define FLOW(a...) dprintf("ahci: " a)
|
||||
@@ -148,7 +146,7 @@ register_sim(device_node *parent)
|
||||
|
||||
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
|
||||
{ string: AHCI_DEVICE_MODULE_NAME }},
|
||||
{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: 255 }},
|
||||
{ B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { ui32: 255 }},
|
||||
{ AHCI_ID_ITEM, B_UINT32_TYPE, { ui32: id }},
|
||||
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE,
|
||||
// { string: AHCI_ID_GENERATOR }},
|
||||
@@ -237,16 +235,12 @@ ahci_register_device(device_node *parent)
|
||||
|
||||
// DMA properties
|
||||
// data must be word-aligned;
|
||||
{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE,
|
||||
{ ui32: 1 }},
|
||||
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1 }},
|
||||
// one S/G block must not cross 64K boundary
|
||||
{ B_BLOCK_DEVICE_DMA_BOUNDARY, B_UINT32_TYPE,
|
||||
{ ui32: 0xffff }},
|
||||
{ B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
|
||||
// max size of S/G block is 16 bits with zero being 64K
|
||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE,
|
||||
{ ui32: 0x10000 }},
|
||||
// see definition of MAX_SG_COUNT
|
||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE,
|
||||
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { ui32: 0x10000 }},
|
||||
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
||||
{ ui32: 32 /* whatever... */ }},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -674,7 +674,7 @@ cd_write(void* cookie, off_t pos, const void* buffer, size_t* _length)
|
||||
|
||||
|
||||
static status_t
|
||||
cd_io(void *cookie, io_request *request)
|
||||
cd_io(void* cookie, io_request* request)
|
||||
{
|
||||
cd_handle* handle = (cd_handle*)cookie;
|
||||
|
||||
@@ -797,7 +797,7 @@ cd_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
|
||||
|
||||
|
||||
static void
|
||||
cd_set_capacity(cd_driver_info *info, uint64 capacity, uint32 blockSize)
|
||||
cd_set_capacity(cd_driver_info* info, uint64 capacity, uint32 blockSize)
|
||||
{
|
||||
TRACE("cd_set_capacity(info = %p, capacity = %Ld, blockSize = %ld)\n",
|
||||
info, capacity, blockSize);
|
||||
@@ -838,7 +838,7 @@ cd_set_capacity(cd_driver_info *info, uint64 capacity, uint32 blockSize)
|
||||
|
||||
|
||||
static void
|
||||
cd_media_changed(cd_driver_info *info, scsi_ccb *request)
|
||||
cd_media_changed(cd_driver_info* info, scsi_ccb* request)
|
||||
{
|
||||
// do a capacity check
|
||||
// TBD: is this a good idea (e.g. if this is an empty CD)?
|
||||
@@ -856,9 +856,9 @@ scsi_periph_callbacks callbacks = {
|
||||
|
||||
|
||||
static float
|
||||
cd_supports_device(device_node *parent)
|
||||
cd_supports_device(device_node* parent)
|
||||
{
|
||||
const char *bus;
|
||||
const char* bus;
|
||||
uint8 deviceType;
|
||||
|
||||
// make sure parent is really the SCSI bus manager
|
||||
@@ -883,20 +883,20 @@ cd_supports_device(device_node *parent)
|
||||
server by the block_io module
|
||||
*/
|
||||
static status_t
|
||||
cd_register_device(device_node *node)
|
||||
cd_register_device(device_node* node)
|
||||
{
|
||||
const scsi_res_inquiry *deviceInquiry = NULL;
|
||||
const scsi_res_inquiry* deviceInquiry = NULL;
|
||||
size_t inquiryLength;
|
||||
uint32 maxBlocks;
|
||||
|
||||
// get inquiry data
|
||||
if (sDeviceManager->get_attr_raw(node, SCSI_DEVICE_INQUIRY_ITEM,
|
||||
(const void **)&deviceInquiry, &inquiryLength, true) != B_OK
|
||||
(const void**)&deviceInquiry, &inquiryLength, true) != B_OK
|
||||
|| inquiryLength < sizeof(deviceInquiry))
|
||||
return B_ERROR;
|
||||
|
||||
// get block limit of underlying hardware to lower it (if necessary)
|
||||
if (sDeviceManager->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM,
|
||||
if (sDeviceManager->get_attr_uint32(node, B_DMA_MAX_TRANSFER_BLOCKS,
|
||||
&maxBlocks, true) != B_OK)
|
||||
maxBlocks = INT_MAX;
|
||||
|
||||
@@ -907,10 +907,8 @@ cd_register_device(device_node *node)
|
||||
|
||||
// ready to register
|
||||
device_attr attrs[] = {
|
||||
// tell block_io whether the device is removable
|
||||
{"removable", B_UINT8_TYPE, {ui8: deviceInquiry->removable_medium}},
|
||||
// impose own max block restriction
|
||||
{B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, {ui32: maxBlocks}},
|
||||
{B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, {ui32: maxBlocks}},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -920,24 +918,21 @@ cd_register_device(device_node *node)
|
||||
|
||||
|
||||
static status_t
|
||||
cd_init_driver(device_node *node, void **cookie)
|
||||
cd_init_driver(device_node* node, void** _cookie)
|
||||
{
|
||||
cd_driver_info *info;
|
||||
status_t status;
|
||||
uint8 removable;
|
||||
|
||||
TRACE("cd_init_driver");
|
||||
|
||||
status = sDeviceManager->get_attr_uint8(node, "removable",
|
||||
uint8 removable;
|
||||
status_t status = sDeviceManager->get_attr_uint8(node, "removable",
|
||||
&removable, false);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
info = (cd_driver_info *)malloc(sizeof(*info));
|
||||
cd_driver_info* info = (cd_driver_info*)malloc(sizeof(cd_driver_info));
|
||||
if (info == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
memset(info, 0, sizeof(cd_driver_info));
|
||||
|
||||
info->dma_resource = new(std::nothrow) DMAResource;
|
||||
if (info->dma_resource == NULL) {
|
||||
@@ -956,8 +951,8 @@ cd_init_driver(device_node *node, void **cookie)
|
||||
&info->device_type, true);
|
||||
|
||||
device_node *parent = sDeviceManager->get_parent_node(node);
|
||||
sDeviceManager->get_driver(parent, (driver_module_info **)&info->scsi,
|
||||
(void **)&info->scsi_device);
|
||||
sDeviceManager->get_driver(parent, (driver_module_info**)&info->scsi,
|
||||
(void**)&info->scsi_device);
|
||||
sDeviceManager->put_node(parent);
|
||||
|
||||
status = sSCSIPeripheral->register_device((periph_device_cookie)info,
|
||||
@@ -968,15 +963,15 @@ cd_init_driver(device_node *node, void **cookie)
|
||||
return status;
|
||||
}
|
||||
|
||||
*cookie = info;
|
||||
*_cookie = info;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cd_uninit_driver(void *_cookie)
|
||||
cd_uninit_driver(void* _cookie)
|
||||
{
|
||||
cd_driver_info *info = (cd_driver_info *)_cookie;
|
||||
cd_driver_info* info = (cd_driver_info*)_cookie;
|
||||
|
||||
sSCSIPeripheral->unregister_device(info->scsi_periph_device);
|
||||
free(info);
|
||||
@@ -984,17 +979,15 @@ cd_uninit_driver(void *_cookie)
|
||||
|
||||
|
||||
static status_t
|
||||
cd_register_child_devices(void *_cookie)
|
||||
cd_register_child_devices(void* _cookie)
|
||||
{
|
||||
cd_driver_info *info = (cd_driver_info *)_cookie;
|
||||
status_t status;
|
||||
char *name;
|
||||
cd_driver_info* info = (cd_driver_info*)_cookie;
|
||||
|
||||
name = sSCSIPeripheral->compose_device_name(info->node, "disk/scsi");
|
||||
char* name = sSCSIPeripheral->compose_device_name(info->node, "disk/scsi");
|
||||
if (name == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
status = sDeviceManager->publish_device(info->node, name,
|
||||
status_t status = sDeviceManager->publish_device(info->node, name,
|
||||
SCSI_CD_DEVICE_MODULE_NAME);
|
||||
|
||||
free(name);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#define _SCSI_CD_H
|
||||
|
||||
|
||||
#include <block_io.h>
|
||||
#include <device_manager.h>
|
||||
#include <scsi_periph.h>
|
||||
#include <scsi.h>
|
||||
|
||||
@@ -441,7 +441,7 @@ das_register_device(device_node *node)
|
||||
return B_ERROR;
|
||||
|
||||
// get block limit of underlying hardware to lower it (if necessary)
|
||||
if (sDeviceManager->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM,
|
||||
if (sDeviceManager->get_attr_uint32(node, B_DMA_MAX_TRANSFER_BLOCKS,
|
||||
&maxBlocks, true) != B_OK)
|
||||
maxBlocks = INT_MAX;
|
||||
|
||||
@@ -455,7 +455,7 @@ das_register_device(device_node *node)
|
||||
// tell block_io whether the device is removable
|
||||
{"removable", B_UINT8_TYPE, {ui8: deviceInquiry->removable_medium}},
|
||||
// impose own max block restriction
|
||||
{B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, {ui32: maxBlocks}},
|
||||
{B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, {ui32: maxBlocks}},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#define _SCSI_DISK_H
|
||||
|
||||
|
||||
#include <block_io.h>
|
||||
#include <device_manager.h>
|
||||
#include <scsi.h>
|
||||
#include <scsi_periph.h>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel generic ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel generic atomizer ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel generic block_io ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel generic dpc ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ;
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel generic block_io ;
|
||||
|
||||
UsePrivateHeaders kernel ;
|
||||
UsePrivateHeaders [ FDirName kernel arch $(TARGET_ARCH) ] ;
|
||||
UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
|
||||
|
||||
# disable debug output, if debugging is disabled
|
||||
if $(DEBUG) = 0 {
|
||||
SubDirCcFlags [ FDefines DEBUG_MAX_LEVEL_FLOW=0 DEBUG_MAX_LEVEL_INFO=0 ] ;
|
||||
}
|
||||
|
||||
KernelAddon block_io :
|
||||
block_io.c
|
||||
io.c
|
||||
virtual_memory.c
|
||||
;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef __BIOS_INFO_H__
|
||||
#define __BIOS_INFO_H__
|
||||
|
||||
// length: 0x84
|
||||
typedef struct tagbios_drive {
|
||||
char name[32]; // 0
|
||||
uint8 bios_id; // 20
|
||||
uint8 padding[3];
|
||||
uint32 cylinder_count; // 24
|
||||
uint32 head_count; // 28
|
||||
uint32 sectors_per_track; // 2c
|
||||
|
||||
uint32 num_chksums; // 30
|
||||
|
||||
struct {
|
||||
uint64 offset; // 34+
|
||||
uint32 len; // 3c+
|
||||
uint32 chksum; // 40+
|
||||
} chksums[5]; // 34
|
||||
} bios_drive;
|
||||
|
||||
extern bios_drive *bios_drive_info;
|
||||
|
||||
extern uint32 boot_calculate_hash( void *buffer, size_t len );
|
||||
|
||||
#endif
|
||||
@@ -1,596 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "block_io_private.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
//#define TRACE_BLOCK_IO
|
||||
#ifdef TRACE_BLOCK_IO
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
uint block_io_buffer_size;
|
||||
sem_id block_io_buffer_lock;
|
||||
struct iovec block_io_buffer_vec[1];
|
||||
void *block_io_buffer_phys;
|
||||
char *block_io_buffer;
|
||||
phys_vecs block_io_buffer_phys_vec;
|
||||
area_id block_io_buffer_area;
|
||||
|
||||
locked_pool_interface *locked_pool;
|
||||
device_manager_info *pnp;
|
||||
|
||||
|
||||
static status_t
|
||||
block_io_open(block_io_device_info *device, const char *path, int openMode,
|
||||
block_io_handle_info **res_handle)
|
||||
{
|
||||
block_io_handle_info *handle;
|
||||
status_t res;
|
||||
|
||||
TRACE(("block_io_open()\n"));
|
||||
|
||||
handle = (block_io_handle_info *)malloc(sizeof(*handle));
|
||||
|
||||
if (handle == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
handle->device = device;
|
||||
|
||||
res = device->interface->open(device->cookie, &handle->cookie);
|
||||
if (res < B_OK)
|
||||
goto err;
|
||||
|
||||
*res_handle = handle;
|
||||
|
||||
TRACE((" opened.\n"));
|
||||
|
||||
return B_OK;
|
||||
|
||||
err:
|
||||
free(handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
block_io_close(block_io_handle_info *handle)
|
||||
{
|
||||
block_io_device_info *device = handle->device;
|
||||
|
||||
TRACE(("block_io_close()\n"));
|
||||
|
||||
device->interface->close(handle->cookie);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
block_io_freecookie(block_io_handle_info *handle)
|
||||
{
|
||||
block_io_device_info *device = handle->device;
|
||||
|
||||
TRACE(("block_io_freecookie()\n"));
|
||||
|
||||
device->interface->free(handle->cookie);
|
||||
free(handle);
|
||||
|
||||
TRACE(("done.\n"));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// TODO: this assumes private R5 kernel functions to be present
|
||||
#if 0
|
||||
/** Verify a checksum that is part of BIOS drive identification.
|
||||
* returns B_OK on success
|
||||
*/
|
||||
|
||||
static status_t
|
||||
verify_checksum(block_io_handle_info *handle, uint64 offset, uint32 len, uint32 chksum)
|
||||
{
|
||||
void *buffer;
|
||||
uint32 readlen;
|
||||
status_t res;
|
||||
|
||||
// SHOW_FLOW( 0, "offset=%lld, len=%ld", offset, len );
|
||||
|
||||
buffer = malloc(len);
|
||||
if (buffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
readlen = len;
|
||||
|
||||
res = block_io_read(handle, offset, buffer, &readlen);
|
||||
if (res < B_OK || readlen < len)
|
||||
goto err;
|
||||
|
||||
// SHOW_FLOW0( 0, "check hash sum" );
|
||||
|
||||
if (boot_calculate_hash(buffer, len) != chksum)
|
||||
goto err;
|
||||
|
||||
// SHOW_FLOW0( 0, "success" );
|
||||
|
||||
free(buffer);
|
||||
return B_OK;
|
||||
|
||||
err:
|
||||
free(buffer);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/** store BIOS drive id in node's attribute */
|
||||
|
||||
static status_t
|
||||
store_bios_drive_in_node(block_io_device_info *device)
|
||||
{
|
||||
device_attr attribute = {
|
||||
B_BLOCK_DEVICE_BIOS_ID, B_UINT8_TYPE, { ui8:
|
||||
device->bios_drive != NULL ? device->bios_drive->bios_id : 0 }
|
||||
};
|
||||
|
||||
return pnp->write_attr(device->node, &attribute);
|
||||
}
|
||||
|
||||
|
||||
/** find BIOS info of drive, if not happened yet.
|
||||
* this must be called whenever someone wants to access BIOS infos about the drive;
|
||||
* there are two reasons to not call this during probe():
|
||||
* - perhaps nobody is interested in BIOS info
|
||||
* - we need a working block_io device to handle lower level driver
|
||||
* restrictions, so this method can only be safely called once the
|
||||
* node has been loaded
|
||||
*/
|
||||
|
||||
static void
|
||||
find_bios_drive_info(block_io_handle_info *handle)
|
||||
{
|
||||
block_io_device_info *device = handle->device;
|
||||
bios_drive *drive = NULL; //, *colliding_drive;
|
||||
char name[32];
|
||||
uint8 bios_id;
|
||||
|
||||
// SHOW_FLOW( 0, "%p", device );
|
||||
|
||||
// return immediately if BIOS info has already been found
|
||||
if (device->bios_drive != NULL)
|
||||
return;
|
||||
|
||||
// check whether BIOS info was found during one of the previous
|
||||
// loads
|
||||
if (pnp->get_attr_uint8(device->node, B_BLOCK_DEVICE_BIOS_ID, &bios_id, false) == B_OK) {
|
||||
TRACE(("use previous BIOS ID 0x%x\n", bios_id));
|
||||
|
||||
// yes, so find the associated data structure
|
||||
if (bios_id != 0) {
|
||||
for (drive = bios_drive_info; drive->bios_id != 0; ++drive) {
|
||||
if (drive->bios_id == bios_id)
|
||||
break;
|
||||
}
|
||||
} else
|
||||
drive = NULL;
|
||||
|
||||
device->bios_drive = drive;
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(name, "PnP %p", device->node);
|
||||
|
||||
// do it the hard way: find a BIOS drive with the same checksums
|
||||
for (drive = bios_drive_info; drive->bios_id != 0; ++drive) {
|
||||
uint32 i;
|
||||
|
||||
// ignore identified BIOS drives
|
||||
if (drive->name[0] != 0)
|
||||
continue;
|
||||
|
||||
TRACE(("verifying drive 0x%x", drive->bios_id));
|
||||
|
||||
for (i = 0; i < drive->num_chksums; ++i) {
|
||||
if (verify_checksum( handle, drive->chksums[i].offset,
|
||||
drive->chksums[i].len, drive->chksums[i].chksum) != B_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == drive->num_chksums)
|
||||
break;
|
||||
}
|
||||
|
||||
if (drive->bios_id == 0) {
|
||||
TRACE(("this is no BIOS drive\n"));
|
||||
// no BIOS drive found
|
||||
goto no_bios_drive;
|
||||
}
|
||||
|
||||
TRACE(("this is BIOS drive 0x%x\n", drive->bios_id));
|
||||
|
||||
// the R5 boot loader assumes that two drives can be distinguished by
|
||||
// - their checksums
|
||||
// - their physical layout
|
||||
// unfortunately, the "physical layout" is something virtual defined by the
|
||||
// BIOS itself, so nobody can verify that;
|
||||
// as a result, we may have two drives with same checksums and different
|
||||
// geometry - having no opportunity to check the geometry, we cannot
|
||||
// distinguish between them.
|
||||
// The simple solution is to modify the boot loader to not take geometry
|
||||
// into account, but without sources, the boot loader cannot be fixed.
|
||||
for (colliding_drive = bios_drive_info; colliding_drive->bios_id != 0; ++colliding_drive) {
|
||||
uint32 i;
|
||||
|
||||
if (drive == colliding_drive)
|
||||
continue;
|
||||
|
||||
if (drive->num_chksums != colliding_drive->num_chksums)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < colliding_drive->num_chksums; ++i) {
|
||||
if (colliding_drive->chksums[i].offset != drive->chksums[i].offset
|
||||
|| colliding_drive->chksums[i].len != drive->chksums[i].len
|
||||
|| colliding_drive->chksums[i].chksum != drive->chksums[i].chksum)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < colliding_drive->num_chksums)
|
||||
continue;
|
||||
|
||||
dprintf("Cannot distinguish between BIOS drives %x and %x without geometry\n",
|
||||
drive->bios_id, colliding_drive->bios_id);
|
||||
|
||||
// this is nasty - we cannot reliable assign BIOS drive number.
|
||||
// if the user has luck, he "only" cannot install a boot manager;
|
||||
// but if the boot drive is affected, he cannot even boot.
|
||||
goto no_bios_drive;
|
||||
}
|
||||
|
||||
TRACE(("store driver \"%s\" in system data\n", name));
|
||||
|
||||
// store name so noone else will test this BIOS drive
|
||||
strcpy(drive->name, name);
|
||||
device->bios_drive = drive;
|
||||
|
||||
// remember that to avoid testing next time
|
||||
store_bios_drive_in_node(device);
|
||||
return;
|
||||
|
||||
no_bios_drive:
|
||||
device->bios_drive = NULL;
|
||||
|
||||
// remember that to avoid testing next time
|
||||
store_bios_drive_in_node(device);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static status_t
|
||||
block_io_ioctl(block_io_handle_info *handle, uint32 op, void *buffer, size_t length)
|
||||
{
|
||||
block_io_device_info *device = handle->device;
|
||||
|
||||
#if 0
|
||||
if (device->is_bios_drive) {
|
||||
switch (op) {
|
||||
case B_GET_BIOS_DRIVE_ID:
|
||||
find_bios_drive_info(handle);
|
||||
|
||||
if (device->bios_drive == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
*(char *)buffer = device->bios_drive->bios_id;
|
||||
return B_OK;
|
||||
|
||||
case B_GET_BIOS_GEOMETRY:
|
||||
{
|
||||
device_geometry *geometry = (device_geometry *)buffer;
|
||||
status_t status;
|
||||
|
||||
find_bios_drive_info(handle);
|
||||
if (device->bios_drive == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
TRACE(("GET_BIOS_GEOMETRY\n"));
|
||||
|
||||
// get real geometry from low level driver
|
||||
status = device->interface->ioctl(handle->cookie, B_GET_GEOMETRY,
|
||||
geometry, sizeof(*geometry));
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// replace entries with bios info retrieved by boot loader
|
||||
geometry->cylinder_count = device->bios_drive->cylinder_count;
|
||||
geometry->head_count = device->bios_drive->head_count;
|
||||
geometry->sectors_per_track = device->bios_drive->sectors_per_track;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return device->interface->ioctl(handle->cookie, op, buffer, length);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
block_io_remove(void *cookie)
|
||||
{
|
||||
#if 0
|
||||
uint8 bios_id;
|
||||
//bios_drive *drive;
|
||||
|
||||
// if this drive has a BIOS ID, remove it from BIOS drive list
|
||||
if (pnp->get_attr_uint8(node, B_BLOCK_DEVICE_BIOS_ID, &bios_id, false) != B_OK
|
||||
|| bios_id == 0 )
|
||||
return;
|
||||
|
||||
// ToDo: this assumes private R5 kernel functions to be present
|
||||
for (drive = bios_drive_info; drive->bios_id != 0; ++drive) {
|
||||
if (drive->bios_id == bios_id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (drive->bios_id != 0) {
|
||||
TRACE(("Marking BIOS device 0x%x as being unknown\n", bios_id));
|
||||
drive->name[0] = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
block_io_init_device(void *_data, void **cookie)
|
||||
{
|
||||
block_device_cookie *data = (block_device_cookie *)_data;
|
||||
block_io_device_info *device;
|
||||
block_device_params params;
|
||||
// const char *name;
|
||||
// char *tmp_name;
|
||||
uint8 is_bios_drive;
|
||||
status_t res;
|
||||
|
||||
TRACE(("block_io_init_device()\n"));
|
||||
|
||||
// extract controller/protocoll restrictions from node
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_DMA_ALIGNMENT, ¶ms.alignment, true) != B_OK)
|
||||
params.alignment = 0;
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, ¶ms.max_blocks, true) != B_OK)
|
||||
params.max_blocks = 0xffffffff;
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_DMA_BOUNDARY, ¶ms.dma_boundary, true) != B_OK)
|
||||
params.dma_boundary = ~0;
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, ¶ms.max_sg_block_size, true) != B_OK)
|
||||
params.max_sg_block_size = 0xffffffff;
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_SG_BLOCKS, ¶ms.max_sg_blocks, true) != B_OK)
|
||||
params.max_sg_blocks = ~0;
|
||||
|
||||
// do some sanity check:
|
||||
// (see scsi/bus_mgr.c)
|
||||
params.max_sg_block_size &= ~params.alignment;
|
||||
|
||||
if (params.alignment > B_PAGE_SIZE) {
|
||||
dprintf("Alignment (0x%lx) must be less then B_PAGE_SIZE\n", params.alignment);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (params.max_sg_block_size < 512) {
|
||||
dprintf("Max s/g block size (0x%lx) is too small\n", params.max_sg_block_size);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (params.dma_boundary < B_PAGE_SIZE - 1) {
|
||||
dprintf("DMA boundary (0x%lx) must be at least B_PAGE_SIZE\n", params.dma_boundary);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (params.max_blocks < 1 || params.max_sg_blocks < 1) {
|
||||
dprintf("Max blocks (%ld) and max s/g blocks (%ld) must be at least 1",
|
||||
params.max_blocks, params.max_sg_blocks);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// allow "only" up to 512 sg entries
|
||||
// (they consume 4KB and can describe up to 2MB virtual cont. memory!)
|
||||
params.max_sg_blocks = min(params.max_sg_blocks, 512);
|
||||
|
||||
if (pnp->get_attr_uint8(data->node, B_BLOCK_DEVICE_IS_BIOS_DRIVE, &is_bios_drive, true) != B_OK)
|
||||
is_bios_drive = false;
|
||||
|
||||
device = (block_io_device_info *)malloc(sizeof(*device));
|
||||
if (device == NULL) {
|
||||
res = B_NO_MEMORY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
memset(device, 0, sizeof(*device));
|
||||
|
||||
device->node = data->node;
|
||||
|
||||
mutex_init(&device->lock, "block_device_mutex");
|
||||
|
||||
#if 0
|
||||
// construct a identifiable name for S/G pool
|
||||
tmp_name = malloc(name + strlen(" sg_lists") + 1);
|
||||
if (tmp_name == NULL) {
|
||||
res = B_NO_MEMORY;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
strcpy(tmp_name, name);
|
||||
strcat(tmp_name, " sg_lists");
|
||||
#endif
|
||||
|
||||
// create S/G pool with initial size 1
|
||||
// (else, we may be on the paging path and have no S/G entries at hand)
|
||||
device->phys_vecs_pool = locked_pool->create(
|
||||
params.max_sg_blocks * sizeof(physical_entry),
|
||||
sizeof( physical_entry ) - 1, 0, 16*1024, 32, 1, "block io sg lists",
|
||||
B_CONTIGUOUS, NULL, NULL, NULL);
|
||||
|
||||
// free(tmp_name);
|
||||
|
||||
if (device->phys_vecs_pool == NULL) {
|
||||
res = B_NO_MEMORY;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
device->params = params;
|
||||
device->is_bios_drive = is_bios_drive != 0;
|
||||
|
||||
pnp->get_driver(device->node, (driver_module_info **)&device->interface,
|
||||
(void **)&device->cookie);
|
||||
|
||||
device->interface->set_device(device->cookie, device);
|
||||
|
||||
TRACE(("done\n"));
|
||||
|
||||
*cookie = device;
|
||||
return B_OK;
|
||||
|
||||
err3:
|
||||
mutex_destroy(&device->lock);
|
||||
free(device);
|
||||
err1:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
block_io_uninit_device(void *_cookie)
|
||||
{
|
||||
block_io_device_info *device = _cookie;
|
||||
|
||||
locked_pool->destroy(device->phys_vecs_pool);
|
||||
mutex_destroy(&device->lock);
|
||||
free(device);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
block_io_init_buffer(void)
|
||||
{
|
||||
physical_entry physicalTable[2];
|
||||
status_t res;
|
||||
|
||||
TRACE(("block_io_init_buffer()\n"));
|
||||
|
||||
block_io_buffer_size = 32*1024;
|
||||
|
||||
block_io_buffer_lock = create_sem(1, "block_io_buffer_mutex");
|
||||
if (block_io_buffer_lock < 0) {
|
||||
res = block_io_buffer_lock;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
res = block_io_buffer_area = create_area("block_io_buffer",
|
||||
(void **)&block_io_buffer, B_ANY_KERNEL_ADDRESS,
|
||||
block_io_buffer_size, B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
|
||||
if (res < 0)
|
||||
goto err2;
|
||||
|
||||
res = get_memory_map(block_io_buffer, block_io_buffer_size, physicalTable, 2);
|
||||
if (res < 0)
|
||||
goto err3;
|
||||
|
||||
block_io_buffer_vec[0].iov_base = block_io_buffer;
|
||||
block_io_buffer_vec[0].iov_len = block_io_buffer_size;
|
||||
|
||||
block_io_buffer_phys_vec.num = 1;
|
||||
block_io_buffer_phys_vec.total_len = block_io_buffer_size;
|
||||
block_io_buffer_phys_vec.vec[0] = physicalTable[0];
|
||||
|
||||
return B_OK;
|
||||
|
||||
err3:
|
||||
delete_area(block_io_buffer_area);
|
||||
err2:
|
||||
delete_sem(block_io_buffer_lock);
|
||||
err1:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
block_io_uninit_buffer(void)
|
||||
{
|
||||
delete_area(block_io_buffer_area);
|
||||
delete_sem(block_io_buffer_lock);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
std_ops(int32 op, ...)
|
||||
{
|
||||
switch (op) {
|
||||
case B_MODULE_INIT:
|
||||
return block_io_init_buffer();
|
||||
case B_MODULE_UNINIT:
|
||||
block_io_uninit_buffer();
|
||||
return B_OK;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module_dependency module_dependencies[] = {
|
||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||
{ LOCKED_POOL_MODULE_NAME, (module_info **)&locked_pool },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
struct device_module_info sBlockIOModule = {
|
||||
{
|
||||
B_BLOCK_IO_DEVICE_MODULE_NAME,
|
||||
0,
|
||||
|
||||
std_ops
|
||||
},
|
||||
|
||||
block_io_init_device,
|
||||
block_io_uninit_device,
|
||||
block_io_remove,
|
||||
|
||||
(status_t (*)(void *, const char *, int, void **))block_io_open,
|
||||
(status_t (*)(void *))block_io_close,
|
||||
(status_t (*)(void *))block_io_freecookie,
|
||||
|
||||
(status_t (*)(void *, off_t, void *, size_t *))block_io_read,
|
||||
(status_t (*)(void *, off_t, const void *, size_t *))block_io_write,
|
||||
NULL, // io
|
||||
|
||||
(status_t (*)(void *, uint32, void *, size_t))block_io_ioctl,
|
||||
|
||||
NULL, // select
|
||||
NULL, // deselect
|
||||
// (status_t (*)(void *, off_t, const iovec *, size_t, size_t *))block_io_readv,
|
||||
// (status_t (*)(void *, off_t, const iovec *, size_t, size_t *))block_io_writev
|
||||
};
|
||||
|
||||
|
||||
block_io_for_driver_interface sBlockIOForDriverModule = {
|
||||
{
|
||||
B_BLOCK_IO_FOR_DRIVER_MODULE_NAME,
|
||||
0,
|
||||
NULL
|
||||
},
|
||||
|
||||
block_io_set_media_params,
|
||||
};
|
||||
|
||||
module_info *modules[] = {
|
||||
&sBlockIOModule.info,
|
||||
&sBlockIOForDriverModule.info,
|
||||
NULL
|
||||
};
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Part of Open block device manager
|
||||
|
||||
Internal header.
|
||||
*/
|
||||
|
||||
#include <block_io.h>
|
||||
#include <locked_pool.h>
|
||||
#include <device_manager.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bios_drive.h"
|
||||
#include "wrapper.h"
|
||||
|
||||
|
||||
// controller restrictions (see block_io.h)
|
||||
typedef struct block_device_params {
|
||||
uint32 alignment;
|
||||
uint32 max_blocks;
|
||||
uint32 dma_boundary;
|
||||
uint32 max_sg_block_size;
|
||||
uint32 max_sg_blocks;
|
||||
} block_device_params;
|
||||
|
||||
|
||||
// device info
|
||||
typedef struct block_io_device_info {
|
||||
device_node *node;
|
||||
block_device_interface *interface;
|
||||
block_device_cookie *cookie;
|
||||
|
||||
mutex lock; // used for access to following variables
|
||||
uint32 block_size;
|
||||
uint32 ld_block_size;
|
||||
uint64 capacity;
|
||||
|
||||
block_device_params params;
|
||||
bool is_bios_drive; // could be a BIOS drive
|
||||
locked_pool_cookie phys_vecs_pool; // pool of temporary phys_vecs
|
||||
bios_drive *bios_drive; // info about corresponding BIOS drive
|
||||
} block_io_device_info;
|
||||
|
||||
|
||||
// file handle info
|
||||
typedef struct block_io_handle_info {
|
||||
block_io_device_info *device;
|
||||
block_device_handle_cookie *cookie;
|
||||
} block_io_handle_info;
|
||||
|
||||
|
||||
// attribute containing BIOS drive ID (or 0, if it's no BIOS drive) (uint8)
|
||||
#define B_BLOCK_DEVICE_BIOS_ID "blkdev/bios_id"
|
||||
|
||||
// transmission buffer data:
|
||||
// size in bytes
|
||||
extern uint block_io_buffer_size;
|
||||
// to use the buffer, you must own this semaphore
|
||||
extern sem_id block_io_buffer_lock;
|
||||
// iovec
|
||||
extern struct iovec block_io_buffer_vec[1];
|
||||
// physical address
|
||||
extern void *block_io_buffer_phys;
|
||||
// virtual address
|
||||
extern char *block_io_buffer;
|
||||
// phys_vec of it (always linear)
|
||||
extern phys_vecs block_io_buffer_phys_vec;
|
||||
// area containing buffer
|
||||
extern area_id block_io_buffer_area;
|
||||
|
||||
extern locked_pool_interface *locked_pool;
|
||||
extern device_manager_info *pnp;
|
||||
|
||||
|
||||
// io.c
|
||||
|
||||
status_t block_io_readv(block_io_handle_info *handle, off_t pos, struct iovec *vec,
|
||||
size_t vec_count, size_t *len);
|
||||
status_t block_io_read(block_io_handle_info *handle, off_t pos, void *buf, size_t *len);
|
||||
ssize_t block_io_writev(block_io_handle_info *handle, off_t pos, struct iovec *vec,
|
||||
size_t vec_count, ssize_t *len);
|
||||
ssize_t block_io_write(block_io_handle_info *handle, off_t pos, void *buf, size_t *len);
|
||||
void block_io_set_media_params(block_io_device_info *device,
|
||||
uint32 block_size, uint32 ld_block_size, uint64 capacity);
|
||||
@@ -1,740 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Part of Open block device manager
|
||||
|
||||
Actual I/O.
|
||||
|
||||
This is hardcode. Think twice before changing something
|
||||
in here.
|
||||
|
||||
Things could become a lot easier with the following restrictions:
|
||||
- stricter data alignment that is sufficient for all controllers
|
||||
(e.g. page-aligned should certainly be)
|
||||
- no partial block access
|
||||
- locked data
|
||||
- always sufficient iovecs for entire transfer
|
||||
|
||||
The last thing is a design problem of the devfs. The first two
|
||||
make sure that we need no buffer anymore, which would make much
|
||||
code unnecessary. The locked data would save much code too - having
|
||||
a sg list as input would make it even more sweeter.
|
||||
|
||||
Obviously these restrictions cannot be enforced for user programs,
|
||||
but at least for transfers from/to disk cache, we could define
|
||||
extra functions with these properties.
|
||||
*/
|
||||
|
||||
|
||||
#include "block_io_private.h"
|
||||
#include "virtual_memory.h"
|
||||
|
||||
|
||||
/** get sg list of iovecs, taking dma boundaries and maximum size of
|
||||
* single s/g entry into account
|
||||
* <vec_offset> must not point byond first iovec
|
||||
*/
|
||||
|
||||
static int
|
||||
block_io_map_iovecs(iovec *vec, size_t vec_count, size_t vec_offset, size_t len,
|
||||
phys_vecs *map, size_t max_phys_entries, size_t dma_boundary,
|
||||
size_t max_sg_block_size)
|
||||
{
|
||||
status_t res;
|
||||
size_t total_len;
|
||||
size_t cur_idx;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
if ((res = get_iovec_memory_map(vec, vec_count, vec_offset, len,
|
||||
map->vec, max_phys_entries, &map->num, &map->total_len)) < B_OK)
|
||||
return res;
|
||||
|
||||
if (dma_boundary == ~0UL && max_sg_block_size >= map->total_len)
|
||||
return B_OK;
|
||||
|
||||
SHOW_FLOW(3, "Checking violation of dma boundary 0x%x and entry size 0x%x",
|
||||
(int)dma_boundary, (int)max_sg_block_size);
|
||||
|
||||
total_len = 0;
|
||||
|
||||
for (cur_idx = 0; cur_idx < map->num; ++cur_idx) {
|
||||
addr_t max_len;
|
||||
|
||||
// calculate space upto next dma boundary crossing
|
||||
max_len = (dma_boundary + 1) - ((addr_t)map->vec[cur_idx].address & dma_boundary);
|
||||
|
||||
// restrict size per sg item
|
||||
max_len = min(max_len, max_sg_block_size);
|
||||
|
||||
SHOW_FLOW(4, "addr=%p, size=%x, max_len=%x, idx=%d, num=%d",
|
||||
map->vec[cur_idx].address, (int)map->vec[cur_idx].size,
|
||||
(int)max_len, (int)cur_idx, (int)map->num);
|
||||
|
||||
if (max_len < map->vec[cur_idx].size) {
|
||||
// split sg block
|
||||
map->num = min(map->num + 1, max_phys_entries);
|
||||
memmove(&map->vec[cur_idx + 1], &map->vec[cur_idx],
|
||||
(map->num - 1 - cur_idx) * sizeof(physical_entry));
|
||||
|
||||
map->vec[cur_idx].size = max_len;
|
||||
map->vec[cur_idx + 1].address = (void *)((addr_t)map->vec[cur_idx + 1].address + max_len);
|
||||
map->vec[cur_idx + 1].size -= max_len;
|
||||
}
|
||||
|
||||
total_len += map->vec[cur_idx].size;
|
||||
}
|
||||
|
||||
// we really have to update total_len - due to block splitting,
|
||||
// some other blocks may got discarded if s/g list became too long
|
||||
map->total_len = total_len;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/** check whether dma alignment restrictions are met
|
||||
* returns true on success
|
||||
* remark: if the user specifies too many iovecs and the unused iovecs
|
||||
* are mis-aligned, it's bad luck as we ignore this case and still
|
||||
* report an alignment problem
|
||||
*/
|
||||
|
||||
static bool
|
||||
block_io_check_alignment(struct iovec *vecs, uint num_vecs,
|
||||
size_t vec_offset, uint alignment)
|
||||
{
|
||||
if (alignment == 0)
|
||||
// no alignment - good boy
|
||||
return true;
|
||||
|
||||
for (; num_vecs > 0; ++vecs, --num_vecs) {
|
||||
// check both begin and end of iovec
|
||||
if ((((addr_t)vecs->iov_base + vec_offset) & alignment) != 0) {
|
||||
SHOW_FLOW(1, "s/g entry not aligned (%p)", vecs->iov_base);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((((addr_t)vecs->iov_base + vecs->iov_len) & alignment) != 0) {
|
||||
SHOW_FLOW(1, "end of s/g entry not aligned (%p)",
|
||||
(void *)((addr_t)vecs->iov_base + vecs->iov_len));
|
||||
return false;
|
||||
}
|
||||
|
||||
vec_offset = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** try to lock iovecs
|
||||
* returns number of locked bytes
|
||||
* (only entire iovecs are attempted to be locked)
|
||||
* remark: if there are too few iovecs, you simply get fewer locked bytes
|
||||
*/
|
||||
|
||||
static size_t
|
||||
block_io_lock_iovecs(struct iovec *vecs, uint num_vecs,
|
||||
size_t vec_offset, size_t len, int flags)
|
||||
{
|
||||
size_t orig_len = len;
|
||||
|
||||
SHOW_FLOW(3, "len = %lu", len);
|
||||
|
||||
for (; len > 0 && num_vecs > 0; ++vecs, --num_vecs) {
|
||||
size_t lock_len;
|
||||
status_t res;
|
||||
|
||||
lock_len = min(vecs->iov_len - vec_offset, len);
|
||||
|
||||
SHOW_FLOW(3, "pos = %p, len = %lu", vecs->iov_base, vecs->iov_len);
|
||||
|
||||
res = lock_memory((void *)((addr_t)vecs->iov_base + vec_offset), lock_len, flags);
|
||||
if (res != B_OK) {
|
||||
SHOW_FLOW(3, "cannot lock: %s", strerror(res));
|
||||
break;
|
||||
}
|
||||
|
||||
len -= lock_len;
|
||||
vec_offset = 0;
|
||||
}
|
||||
|
||||
SHOW_FLOW( 3, "remaining len=%lu", len);
|
||||
|
||||
return orig_len - len;
|
||||
}
|
||||
|
||||
|
||||
/** unlock iovecs */
|
||||
|
||||
static void
|
||||
block_io_unlock_iovecs(struct iovec *vecs, uint num_vecs,
|
||||
size_t vec_offset, size_t len, int flags)
|
||||
{
|
||||
SHOW_FLOW(3, "len = %lu", len);
|
||||
|
||||
for (; len > 0; ++vecs, --num_vecs) {
|
||||
size_t lock_len;
|
||||
|
||||
lock_len = min(vecs->iov_len - vec_offset, len);
|
||||
|
||||
if (unlock_memory((void *)((addr_t)vecs->iov_base + vec_offset), lock_len,
|
||||
flags) != B_OK)
|
||||
panic( "Cannot unlock previously locked memory!" );
|
||||
|
||||
len -= lock_len;
|
||||
vec_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** copy data from/to transfer buffer;
|
||||
* remark: if iovecs are missing, copying is aborted
|
||||
*/
|
||||
|
||||
static void
|
||||
block_io_copy_buffer(char *buffer, struct iovec *vecs, uint num_vecs,
|
||||
size_t vec_offset, size_t len, bool to_buffer)
|
||||
{
|
||||
for (; len > 0 && num_vecs > 0; ++vecs, --num_vecs) {
|
||||
size_t bytes;
|
||||
|
||||
bytes = min(len, vecs->iov_len - vec_offset);
|
||||
|
||||
if (to_buffer)
|
||||
memcpy(buffer, (void *)((addr_t)vecs->iov_base + vec_offset), bytes);
|
||||
else
|
||||
memcpy((void *)((addr_t)vecs->iov_base + vec_offset), buffer, bytes);
|
||||
|
||||
buffer += bytes;
|
||||
vec_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** determine number of bytes described by iovecs */
|
||||
|
||||
static size_t
|
||||
block_io_iovec_len(struct iovec *vecs, uint num_vecs, size_t vec_offset)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
for (; num_vecs > 0; ++vecs, --num_vecs) {
|
||||
len += vecs->iov_len - vec_offset;
|
||||
vec_offset = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/** main beast to execute i/o transfer
|
||||
* as <need_locking> and <write> is usual const, we really want to inline
|
||||
* it - this makes this function much smaller in a given instance
|
||||
* <need_locking> - data must be locked before transferring it
|
||||
* <vec> - should be locked, though it's probably not really necessary
|
||||
*/
|
||||
|
||||
static inline status_t
|
||||
block_io_readwrite(block_io_handle_info *handle, off_t pos, struct iovec *vec,
|
||||
int vec_count, size_t *total_len, bool need_locking, bool write)
|
||||
{
|
||||
block_io_device_info *device = handle->device;
|
||||
uint32 block_size, ld_block_size;
|
||||
uint64 capacity;
|
||||
bool need_buffer;
|
||||
status_t res = B_OK;
|
||||
|
||||
size_t len = *total_len;
|
||||
size_t orig_len = len;
|
||||
size_t vec_offset;
|
||||
|
||||
phys_vecs *phys_vecs;
|
||||
|
||||
SHOW_FLOW(3, "pos = %Ld, len = %lu, need_locking = %d, write = %d, vec_count = %d",
|
||||
pos, len, need_locking, write, vec_count);
|
||||
|
||||
// general properties may get modified, so make a copy first
|
||||
/*device->interface->get_media_params( handle->handle_cookie,
|
||||
&block_size, &ld_block_size, &capacity );*/
|
||||
ACQUIRE_BEN(&device->lock);
|
||||
block_size = device->block_size;
|
||||
ld_block_size = device->ld_block_size;
|
||||
capacity = device->capacity;
|
||||
RELEASE_BEN(&device->lock);
|
||||
|
||||
if (capacity == 0) {
|
||||
res = B_DEV_NO_MEDIA;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (block_size == 0) {
|
||||
res = B_DEV_CONFIGURATION_ERROR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
phys_vecs = locked_pool->alloc(device->phys_vecs_pool);
|
||||
|
||||
SHOW_FLOW0(3, "got phys_vecs");
|
||||
|
||||
// offset in active iovec (can span even byond first iovec)
|
||||
vec_offset = 0;
|
||||
|
||||
while (len > 0) {
|
||||
//off_t block_pos;
|
||||
uint64 block_pos;
|
||||
uint32 block_ofs;
|
||||
size_t cur_len;
|
||||
|
||||
size_t cur_blocks;
|
||||
struct iovec *cur_vecs;
|
||||
size_t cur_vec_count;
|
||||
size_t cur_vec_offset;
|
||||
|
||||
size_t bytes_transferred;
|
||||
|
||||
SHOW_FLOW(3, "current len = %lu", len);
|
||||
|
||||
// skip handled iovecs
|
||||
while (vec_count > 0 && vec_offset >= vec->iov_len) {
|
||||
vec_offset -= vec->iov_len;
|
||||
++vec;
|
||||
--vec_count;
|
||||
}
|
||||
|
||||
// having too few iovecs is handled in the following way:
|
||||
// 1. if no other problem occurs, lock_iovecs restrict transfer
|
||||
// up to the last block fully described by iovecs
|
||||
// 2. if only a partial block is described, we fallback to
|
||||
// buffered transfer because lock_iovecs cannot give you
|
||||
// a whole block
|
||||
// 3. whenever buffered transfer is used, an explicit test for
|
||||
// iovec shortage is done and transmission is restricted up to
|
||||
// and including the last block that has an iovec; copying from/to
|
||||
// buffer stops when no iovec is left (copy_buffer) and thus
|
||||
// restricts transfer appropriately
|
||||
// 4. whenever all iovecs are consumed, we arrive at this piece of
|
||||
// code and abort
|
||||
if (vec_count == 0) {
|
||||
SHOW_FLOW0(3, "vec too short");
|
||||
res = B_BAD_VALUE;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
// get block index / start offset in block
|
||||
if (ld_block_size) {
|
||||
block_pos = pos >> ld_block_size;
|
||||
block_ofs = pos - (block_pos << ld_block_size);
|
||||
} else {
|
||||
block_pos = pos / block_size;
|
||||
block_ofs = pos - block_pos * block_size;
|
||||
}
|
||||
|
||||
// read requests beyond end of volume must be ignored without notice
|
||||
if (block_pos >= capacity) {
|
||||
SHOW_FLOW0(1, "transfer starts beyond end of device");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
SHOW_FLOW(3, "block_pos = %Ld, block_ofs = %lu", block_pos, block_ofs);
|
||||
|
||||
// check whether a buffered transfer is required:
|
||||
// 1. partial block transfer:
|
||||
// 1a. transfer starts within block
|
||||
// 1b. transfer finishes within block
|
||||
// 2. dma alignment problem
|
||||
|
||||
// 1a and 2 is handled immediately, case 1b is delayed: we transmit
|
||||
// whole blocks until the last (partial) block is reached and handle
|
||||
// it seperately; therefore we only check for len < block_size, e.g.
|
||||
// for a last partial block (we could do better, but you get what
|
||||
// you deserve)
|
||||
need_buffer = block_ofs != 0
|
||||
|| len < block_size
|
||||
|| !block_io_check_alignment(vec, vec_count, vec_offset, device->params.alignment);
|
||||
|
||||
retry:
|
||||
if (need_buffer) {
|
||||
size_t tmp_len;
|
||||
|
||||
// argh! - need buffered transfer
|
||||
SHOW_FLOW(1, "buffer required: len=%ld, block_ofs=%ld",
|
||||
len, block_ofs);
|
||||
|
||||
acquire_sem(block_io_buffer_lock);
|
||||
|
||||
// nobody helps us if there are too few iovecs, so test
|
||||
// for that explicitely
|
||||
// (case that tmp_len = 0 is already checked above; if not,
|
||||
// we would get trouble when we try to round up to next
|
||||
// block size, which would lead to zero, making trouble
|
||||
// during lock)
|
||||
tmp_len = block_io_iovec_len(vec, vec_count, vec_offset);
|
||||
tmp_len = min(tmp_len, len);
|
||||
|
||||
SHOW_FLOW(3, "tmp_len: %lu", tmp_len);
|
||||
|
||||
if (write && (block_ofs != 0 || tmp_len < block_size)) {
|
||||
// partial block write - need to read block first
|
||||
// we always handle one block only to keep things simple
|
||||
cur_blocks = 1;
|
||||
|
||||
SHOW_FLOW0(3, "partial write at beginning: reading content of first block");
|
||||
|
||||
// temporarily restrict the buffer's S/G list size to how much
|
||||
// we actually want to read
|
||||
block_io_buffer_phys_vec.total_len = block_size;
|
||||
block_io_buffer_phys_vec.vec[0].size = block_size;
|
||||
|
||||
res = device->interface->read(handle->cookie,
|
||||
&block_io_buffer_phys_vec, block_pos,
|
||||
cur_blocks, block_size, &bytes_transferred);
|
||||
|
||||
block_io_buffer_phys_vec.total_len = block_io_buffer_size;
|
||||
block_io_buffer_phys_vec.vec[0].size = block_io_buffer_size;
|
||||
} else {
|
||||
// alignment problem or partial block read - find out how many
|
||||
// blocks are spanned by this transfer
|
||||
cur_blocks = (tmp_len + block_ofs + block_size - 1) / block_size;
|
||||
|
||||
SHOW_FLOW(3, "cur_blocks: %ld", cur_blocks);
|
||||
|
||||
// restrict block count to buffer size
|
||||
if (cur_blocks * block_size > block_io_buffer_size)
|
||||
cur_blocks = block_io_buffer_size / block_size;
|
||||
}
|
||||
|
||||
// copy data into buffer before write
|
||||
// (calculate number of bytes to copy carefully!)
|
||||
if (write) {
|
||||
SHOW_FLOW(3, "copy data to buffer (%ld bytes)",
|
||||
cur_blocks * block_size - block_ofs);
|
||||
block_io_copy_buffer(block_io_buffer + block_ofs,
|
||||
vec, vec_count, vec_offset, cur_blocks * block_size - block_ofs,
|
||||
true);
|
||||
}
|
||||
|
||||
cur_vecs = block_io_buffer_vec;
|
||||
cur_vec_count = 1;
|
||||
cur_vec_offset = 0;
|
||||
} else {
|
||||
// no buffer needed
|
||||
if (ld_block_size)
|
||||
cur_blocks = len >> ld_block_size;
|
||||
else
|
||||
cur_blocks = len / block_size;
|
||||
|
||||
cur_vecs = vec;
|
||||
cur_vec_count = vec_count;
|
||||
cur_vec_offset = vec_offset;
|
||||
}
|
||||
|
||||
SHOW_FLOW(3, "cur_blocks = %lu, cur_vec_offset = %lu, cur_vec_count = %lu",
|
||||
cur_blocks, cur_vec_offset, cur_vec_count);
|
||||
|
||||
// restrict transfer size to device limits and media capacity
|
||||
cur_blocks = min(cur_blocks, device->params.max_blocks);
|
||||
|
||||
if (block_pos + cur_blocks > capacity)
|
||||
cur_blocks = capacity - block_pos;
|
||||
|
||||
SHOW_FLOW(3, "after applying size restriction: cur_blocks = %lu", cur_blocks);
|
||||
|
||||
cur_len = cur_blocks * block_size;
|
||||
|
||||
if (need_locking) {
|
||||
// lock data
|
||||
// side-node: we also lock the transfer buffer to simplify code
|
||||
|
||||
// if n bytes are to be transferred, we try to lock
|
||||
// n bytes, then n/2, n/4 etc. until we succeed
|
||||
// this is needed because locking fails for entire iovecs only
|
||||
for (; cur_len > 0; cur_blocks >>= 1, cur_len = cur_blocks * block_size) {
|
||||
size_t locked_len;
|
||||
|
||||
SHOW_FLOW(3, "trying to lock %lu bytes", cur_len);
|
||||
|
||||
locked_len = block_io_lock_iovecs(cur_vecs, cur_vec_count,
|
||||
cur_vec_offset, cur_len, B_DMA_IO | (write ? 0 : B_READ_DEVICE));
|
||||
|
||||
if (locked_len == cur_len)
|
||||
break;
|
||||
|
||||
// couldn't lock all we want
|
||||
SHOW_FLOW0(3, "couldn't lock all bytes");
|
||||
|
||||
if (locked_len > block_size) {
|
||||
// locked at least one block - we are happy
|
||||
SHOW_FLOW0(3, "transmission length restricted to locked bytes");
|
||||
cur_blocks = locked_len / block_size;
|
||||
cur_len = cur_blocks * block_size;
|
||||
break;
|
||||
}
|
||||
|
||||
// got less then one block locked - unlock and retry
|
||||
SHOW_FLOW0(3, "too few bytes locked - trying again with fewer bytes");
|
||||
|
||||
block_io_unlock_iovecs(cur_vecs, cur_vec_count, cur_vec_offset, locked_len,
|
||||
B_DMA_IO | (write ? 0 : B_READ_DEVICE));
|
||||
}
|
||||
|
||||
if (cur_len == 0) {
|
||||
// didn't manage to lock at least one block
|
||||
// -> fallback to buffered transfer
|
||||
SHOW_FLOW0(3, "locking failed");
|
||||
|
||||
if (need_buffer) {
|
||||
// error locking transfer buffer?
|
||||
// that's impossible - it is locked already!
|
||||
panic("Cannot lock scratch buffer\n");
|
||||
res = B_ERROR;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
need_buffer = true;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
// data is locked and all restrictions are obeyed now;
|
||||
// time to setup sg list
|
||||
SHOW_FLOW0(3, "Creating SG list");
|
||||
|
||||
res = block_io_map_iovecs(cur_vecs, cur_vec_count, cur_vec_offset, cur_len,
|
||||
phys_vecs, device->params.max_sg_blocks, device->params.dma_boundary,
|
||||
device->params.max_sg_block_size);
|
||||
|
||||
if (res < 0) {
|
||||
SHOW_FLOW(3, "failed - %s", strerror(res));
|
||||
goto cannot_map;
|
||||
}
|
||||
|
||||
if (phys_vecs->total_len < cur_len) {
|
||||
// we hit some sg limit - restrict transfer appropriately
|
||||
cur_blocks = phys_vecs->total_len / block_size;
|
||||
|
||||
SHOW_FLOW(3, "transmission to complex - restricted to %d blocks", (int)cur_blocks);
|
||||
|
||||
if (cur_blocks == 0) {
|
||||
// oh no - not even one block is left; use transfer buffer instead
|
||||
SHOW_FLOW0(3, "SG too small to handle even one block");
|
||||
|
||||
if (need_locking) {
|
||||
block_io_unlock_iovecs(cur_vecs, cur_vec_count, cur_vec_offset,
|
||||
cur_len, B_DMA_IO | (write ? 0 : B_READ_DEVICE));
|
||||
}
|
||||
|
||||
if (need_buffer) {
|
||||
// we are already using the transfer buffer
|
||||
// this case is impossible as transfer buffer is linear!
|
||||
panic("Scratch buffer turned out to be too fragmented !?\n");
|
||||
}
|
||||
|
||||
SHOW_FLOW0(3, "Falling back to buffered transfer");
|
||||
|
||||
need_buffer = true;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
// reflect rounded len in sg list
|
||||
phys_vecs->total_len = cur_blocks * block_size;
|
||||
}
|
||||
|
||||
// at least - let the bytes flow
|
||||
SHOW_FLOW(2, "Transmitting %d bytes @%Ld",
|
||||
(int)phys_vecs->total_len, block_pos);
|
||||
|
||||
if (write) {
|
||||
res = device->interface->write(handle->cookie,
|
||||
phys_vecs, block_pos, cur_blocks, block_size, &bytes_transferred);
|
||||
} else {
|
||||
res = device->interface->read(handle->cookie,
|
||||
phys_vecs, block_pos, cur_blocks, block_size, &bytes_transferred);
|
||||
}
|
||||
|
||||
SHOW_FLOW(3, "Transfer of %d bytes completed (%s)",
|
||||
(int)bytes_transferred, strerror(res));
|
||||
|
||||
cannot_map:
|
||||
// unlock data
|
||||
if (need_locking) {
|
||||
block_io_unlock_iovecs(cur_vecs, cur_vec_count, cur_vec_offset,
|
||||
cur_len, B_DMA_IO | (write ? 0 : B_READ_DEVICE));
|
||||
}
|
||||
|
||||
if (res < 0)
|
||||
goto err3;
|
||||
|
||||
if (need_buffer) {
|
||||
// adjust transfer size by gap skipped at beginning of blocks
|
||||
bytes_transferred -= block_ofs;
|
||||
|
||||
// if we had to round up to block size, adjust transfer as well
|
||||
if (bytes_transferred > len)
|
||||
bytes_transferred = len;
|
||||
|
||||
// if transfer buffer is used for read, copy result from it
|
||||
if (!write) {
|
||||
SHOW_FLOW(3, "copying data back from buffer (%ld bytes)",
|
||||
bytes_transferred);
|
||||
block_io_copy_buffer(block_io_buffer + block_ofs,
|
||||
vec, vec_count, vec_offset, bytes_transferred, false);
|
||||
}
|
||||
|
||||
release_sem(block_io_buffer_lock);
|
||||
}
|
||||
|
||||
len -= bytes_transferred;
|
||||
vec_offset += bytes_transferred;
|
||||
pos += bytes_transferred;
|
||||
}
|
||||
|
||||
locked_pool->free(device->phys_vecs_pool, phys_vecs);
|
||||
|
||||
SHOW_FLOW0(3, "done");
|
||||
|
||||
return B_OK;
|
||||
|
||||
err3:
|
||||
if (need_buffer)
|
||||
release_sem(block_io_buffer_lock);
|
||||
err2:
|
||||
locked_pool->free(device->phys_vecs_pool, phys_vecs);
|
||||
err:
|
||||
SHOW_FLOW(3, "done with error %s", strerror(res));
|
||||
|
||||
// we haven't transferred all data - tell caller about
|
||||
*total_len = orig_len - len;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
block_io_readv_int(block_io_handle_info *handle, off_t pos, struct iovec *vec,
|
||||
size_t vec_count, size_t *len, bool need_locking)
|
||||
{
|
||||
return block_io_readwrite(handle, pos, vec, vec_count, len, need_locking, false);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
block_io_writev_int(block_io_handle_info *handle, off_t pos, struct iovec *vec,
|
||||
size_t vec_count, size_t *len, bool need_locking)
|
||||
{
|
||||
return block_io_readwrite(handle, pos, vec, vec_count, len, need_locking, true);
|
||||
}
|
||||
|
||||
|
||||
/** generic read(v)/write(v) routine;
|
||||
* iovecs are locked during transfer
|
||||
* inlining it leads to overall code reduction as <write> is const
|
||||
*/
|
||||
|
||||
static inline status_t
|
||||
block_io_readwritev(block_io_handle_info *handle, off_t pos, struct iovec *vec,
|
||||
size_t vec_count, size_t *len, bool write)
|
||||
|
||||
{
|
||||
status_t res;
|
||||
struct iovec *cur_vec;
|
||||
size_t left;
|
||||
size_t total_len;
|
||||
|
||||
if ((res = lock_memory(vec, vec_count * sizeof(vec[0]), 0)) < 0)
|
||||
return res;
|
||||
|
||||
// there is an error in the BeBook: *len does _not_ contain correct
|
||||
// total length on call - you have to calculate that yourself
|
||||
total_len = 0;
|
||||
|
||||
for (cur_vec = vec, left = vec_count; left > 0; ++cur_vec, --left) {
|
||||
total_len += cur_vec->iov_len;
|
||||
}
|
||||
|
||||
*len = total_len;
|
||||
|
||||
if (write)
|
||||
res = block_io_writev_int(handle, pos, vec, vec_count, len, true);
|
||||
else
|
||||
res = block_io_readv_int(handle, pos, vec, vec_count, len, true);
|
||||
|
||||
unlock_memory(vec, vec_count * sizeof(vec[0]), 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
block_io_readv(block_io_handle_info *handle, off_t pos, struct iovec *vec,
|
||||
size_t vec_count, size_t *len)
|
||||
{
|
||||
/* SHOW_FLOW( 4, "len=%d", (int)*len );
|
||||
|
||||
for( cur_vec = vec, left = vec_count; left > 0; ++cur_vec, --left ) {
|
||||
SHOW_FLOW( 4, "pos=%x, size=%d",
|
||||
(int)cur_vec->iov_base, (int)cur_vec->iov_len );
|
||||
}*/
|
||||
|
||||
return block_io_readwritev(handle, pos, vec, vec_count, len, false);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
block_io_read(block_io_handle_info *handle, off_t pos, void *buf, size_t *len)
|
||||
{
|
||||
iovec vec[1];
|
||||
|
||||
vec[0].iov_base = buf;
|
||||
vec[0].iov_len = *len;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
// This assumes that the thread stack is not paged,
|
||||
// else you want to use block_io_readv
|
||||
// But this is not a problem, since kernel stacks
|
||||
// are always paged in (since they can be used by
|
||||
// an interrupt at any time)
|
||||
return block_io_readv_int(handle, pos, vec, 1, len, true);
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
block_io_writev(block_io_handle_info *handle, off_t pos, struct iovec *vec,
|
||||
size_t vec_count, ssize_t *len)
|
||||
{
|
||||
return block_io_readwritev(handle, pos, vec, vec_count, len, true);
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
block_io_write(block_io_handle_info *handle, off_t pos, void *buf, size_t *len)
|
||||
{
|
||||
iovec vec[1];
|
||||
|
||||
vec[0].iov_base = buf;
|
||||
vec[0].iov_len = *len;
|
||||
|
||||
// see block_io_read
|
||||
return block_io_writev_int(handle, pos, vec, 1, len, true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
block_io_set_media_params(block_io_device_info *device, uint32 block_size,
|
||||
uint32 ld_block_size, uint64 capacity)
|
||||
{
|
||||
SHOW_FLOW(3, "block_size = %lu, ld_block_size = %lu, capacity = %Lu\n", block_size,
|
||||
ld_block_size, capacity);
|
||||
|
||||
ACQUIRE_BEN(&device->lock);
|
||||
|
||||
device->block_size = block_size;
|
||||
device->ld_block_size = ld_block_size;
|
||||
device->capacity = capacity;
|
||||
|
||||
RELEASE_BEN(&device->lock);
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*
|
||||
VM helper functions.
|
||||
|
||||
Important assumption: get_memory_map must combine adjacent
|
||||
physical pages, so contignous memory always leads to a S/G
|
||||
list of length one.
|
||||
*/
|
||||
|
||||
#include "virtual_memory.h"
|
||||
#include "wrapper.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/** get sg list of iovec
|
||||
* TBD: this should be moved to somewhere in kernel
|
||||
*/
|
||||
|
||||
status_t
|
||||
get_iovec_memory_map(iovec *vec, size_t vec_count, size_t vec_offset, size_t len,
|
||||
physical_entry *map, size_t max_entries, size_t *num_entries, size_t *mapped_len)
|
||||
{
|
||||
size_t cur_idx;
|
||||
size_t left_len;
|
||||
|
||||
SHOW_FLOW(3, "vec_count=%lu, vec_offset=%lu, len=%lu, max_entries=%lu",
|
||||
vec_count, vec_offset, len, max_entries);
|
||||
|
||||
// skip iovec blocks if needed
|
||||
while (vec_count > 0 && vec_offset > vec->iov_len) {
|
||||
vec_offset -= vec->iov_len;
|
||||
--vec_count;
|
||||
++vec;
|
||||
}
|
||||
|
||||
for (left_len = len, cur_idx = 0; left_len > 0 && vec_count > 0 && cur_idx < max_entries;) {
|
||||
char *range_start;
|
||||
size_t range_len;
|
||||
status_t res;
|
||||
size_t cur_num_entries, cur_mapped_len;
|
||||
uint32 tmp_idx;
|
||||
|
||||
SHOW_FLOW( 3, "left_len=%d, vec_count=%d, cur_idx=%d",
|
||||
(int)left_len, (int)vec_count, (int)cur_idx );
|
||||
|
||||
// map one iovec
|
||||
range_start = (char *)vec->iov_base + vec_offset;
|
||||
range_len = min( vec->iov_len - vec_offset, left_len );
|
||||
|
||||
SHOW_FLOW( 3, "range_start=%x, range_len=%x",
|
||||
(int)range_start, (int)range_len );
|
||||
|
||||
vec_offset = 0;
|
||||
|
||||
if ((res = get_memory_map(range_start, range_len, &map[cur_idx],
|
||||
max_entries - cur_idx)) != B_OK) {
|
||||
// according to docu, no error is ever reported - argh!
|
||||
SHOW_ERROR(1, "invalid io_vec passed (%s)", strerror(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
// stupid: get_memory_map does neither tell how many sg blocks
|
||||
// are used nor whether there were enough sg blocks at all;
|
||||
// -> determine that manually
|
||||
cur_mapped_len = 0;
|
||||
cur_num_entries = 0;
|
||||
|
||||
for (tmp_idx = cur_idx; tmp_idx < max_entries; ++tmp_idx) {
|
||||
if (map[tmp_idx].size == 0)
|
||||
break;
|
||||
|
||||
cur_mapped_len += map[tmp_idx].size;
|
||||
++cur_num_entries;
|
||||
}
|
||||
|
||||
if (cur_mapped_len == 0) {
|
||||
panic("get_memory_map() returned empty list; left_len=%d, idx=%d/%d",
|
||||
(int)left_len, (int)cur_idx, (int)max_entries);
|
||||
SHOW_ERROR(2, "get_memory_map() returned empty list; left_len=%d, idx=%d/%d",
|
||||
(int)left_len, (int)cur_idx, (int)max_entries);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
SHOW_FLOW( 3, "cur_num_entries=%d, cur_mapped_len=%x",
|
||||
(int)cur_num_entries, (int)cur_mapped_len );
|
||||
|
||||
// try to combine with previous sg block
|
||||
if (cur_num_entries > 0 && cur_idx > 0
|
||||
&& map[cur_idx].address == (char *)map[cur_idx - 1].address + map[cur_idx - 1].size) {
|
||||
SHOW_FLOW0( 3, "combine with previous chunk" );
|
||||
map[cur_idx - 1].size += map[cur_idx].size;
|
||||
memcpy(&map[cur_idx], &map[cur_idx + 1], (cur_num_entries - 1) * sizeof(map[0]));
|
||||
--cur_num_entries;
|
||||
}
|
||||
|
||||
cur_idx += cur_num_entries;
|
||||
left_len -= cur_mapped_len;
|
||||
|
||||
// advance iovec if current one is described completely
|
||||
if (cur_mapped_len == range_len) {
|
||||
++vec;
|
||||
--vec_count;
|
||||
}
|
||||
}
|
||||
|
||||
*num_entries = cur_idx;
|
||||
*mapped_len = len - left_len;
|
||||
|
||||
SHOW_FLOW( 3, "num_entries=%d, mapped_len=%x",
|
||||
(int)*num_entries, (int)*mapped_len );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _VIRTUAL_MEMORY_H
|
||||
#define _VIRTUAL_MEMORY_H
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <iovec.h>
|
||||
|
||||
|
||||
// get memory map of iovec
|
||||
extern status_t get_iovec_memory_map(iovec *vec, size_t vecCount,
|
||||
size_t vecOffset, size_t length, physical_entry *map,
|
||||
size_t maxMapEntries, size_t *_numEntries,
|
||||
size_t *_mappedLength);
|
||||
|
||||
#endif /* _VIRTUAL_MEMORY_H */
|
||||
@@ -1,90 +0,0 @@
|
||||
#ifndef _WRAPPER_H
|
||||
#define _WRAPPER_H
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <lock.h>
|
||||
|
||||
|
||||
// benaphores
|
||||
|
||||
#define INIT_BEN(x, prefix) (mutex_init_etc(x, prefix, MUTEX_FLAG_CLONE_NAME), \
|
||||
B_OK)
|
||||
#define DELETE_BEN(x) mutex_destroy(x)
|
||||
#define ACQUIRE_BEN(x) mutex_lock(x)
|
||||
#define RELEASE_BEN(x) mutex_unlock(x)
|
||||
|
||||
// debug output
|
||||
|
||||
#ifdef DEBUG_WAIT_ON_MSG
|
||||
# define DEBUG_WAIT snooze( DEBUG_WAIT_ON_MSG );
|
||||
#else
|
||||
# define DEBUG_WAIT
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_WAIT_ON_ERROR
|
||||
# define DEBUG_WAIT_ERROR snooze( DEBUG_WAIT_ON_ERROR );
|
||||
#else
|
||||
# define DEBUG_WAIT_ERROR
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_MAX_LEVEL_FLOW
|
||||
# define DEBUG_MAX_LEVEL_FLOW 4
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_MAX_LEVEL_INFO
|
||||
# define DEBUG_MAX_LEVEL_INFO 4
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_MAX_LEVEL_ERROR
|
||||
# define DEBUG_MAX_LEVEL_ERROR 4
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_MSG_PREFIX
|
||||
# define DEBUG_MSG_PREFIX ""
|
||||
#endif
|
||||
|
||||
#ifndef debug_level_flow
|
||||
# define debug_level_flow 0
|
||||
#endif
|
||||
|
||||
#ifndef debug_level_info
|
||||
# define debug_level_info 1
|
||||
#endif
|
||||
|
||||
#ifndef debug_level_error
|
||||
# define debug_level_error 2
|
||||
#endif
|
||||
|
||||
#define FUNC_NAME DEBUG_MSG_PREFIX, __FUNCTION__
|
||||
|
||||
#define SHOW_FLOW(seriousness, format, param...) \
|
||||
do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \
|
||||
dprintf( "%s%s: "format"\n", FUNC_NAME, param ); DEBUG_WAIT \
|
||||
}} while( 0 )
|
||||
|
||||
#define SHOW_FLOW0(seriousness, format) \
|
||||
do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \
|
||||
dprintf( "%s%s: "format"\n", FUNC_NAME); DEBUG_WAIT \
|
||||
}} while( 0 )
|
||||
|
||||
#define SHOW_INFO(seriousness, format, param...) \
|
||||
do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \
|
||||
dprintf( "%s%s: "format"\n", FUNC_NAME, param ); DEBUG_WAIT \
|
||||
}} while( 0 )
|
||||
|
||||
#define SHOW_INFO0(seriousness, format) \
|
||||
do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \
|
||||
dprintf( "%s%s: "format"\n", FUNC_NAME); DEBUG_WAIT \
|
||||
}} while( 0 )
|
||||
|
||||
#define SHOW_ERROR(seriousness, format, param...) \
|
||||
do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \
|
||||
dprintf( "%s%s: "format"\n", FUNC_NAME, param ); DEBUG_WAIT_ERROR \
|
||||
}} while( 0 )
|
||||
|
||||
#define SHOW_ERROR0(seriousness, format) \
|
||||
do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \
|
||||
dprintf( "%s%s: "format"\n", FUNC_NAME); DEBUG_WAIT_ERROR \
|
||||
}} while( 0 )
|
||||
|
||||
#endif /* _BENAPHORE_H */
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <bus/IDE.h>
|
||||
#include <ide_types.h>
|
||||
#include <ide_adapter.h>
|
||||
#include <block_io.h>
|
||||
#include <lendian_bitfield.h>
|
||||
|
||||
#define debug_level_flow 0
|
||||
@@ -656,18 +655,20 @@ ide_adapter_publish_controller(device_node *parent, uint16 bus_master_base,
|
||||
// command queuing always works (unless controller is buggy)
|
||||
{ IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: can_cq }},
|
||||
// choose any name here
|
||||
{ IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: controller_name }},
|
||||
{ IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE,
|
||||
{ string: controller_name }},
|
||||
|
||||
// DMA properties
|
||||
// data must be word-aligned;
|
||||
// warning: some controllers are more picky!
|
||||
{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: dma_alignment /*1*/}},
|
||||
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: dma_alignment /*1*/}},
|
||||
// one S/G block must not cross 64K boundary
|
||||
{ B_BLOCK_DEVICE_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: dma_boundary/*0xffff*/ }},
|
||||
{ B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: dma_boundary/*0xffff*/ }},
|
||||
// max size of S/G block is 16 bits with zero being 64K
|
||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE, { ui32: max_sg_block_size/*0x10000*/ }},
|
||||
// see definition of MAX_SG_COUNT
|
||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE, { ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
||||
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE,
|
||||
{ ui32: max_sg_block_size/*0x10000*/ }},
|
||||
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
||||
{ ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
||||
|
||||
// private data to find controller
|
||||
{ IDE_ADAPTER_BUS_MASTER_BASE, B_UINT16_TYPE, { ui16: bus_master_base }},
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <scsi_periph.h>
|
||||
#include <block_io.h>
|
||||
#include <device_manager.h>
|
||||
|
||||
#include "io_requests.h"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "dma_resources.h"
|
||||
|
||||
#include <block_io.h>
|
||||
#include <device_manager.h>
|
||||
|
||||
#include <kernel.h>
|
||||
#include <util/AutoLock.h>
|
||||
@@ -124,23 +124,23 @@ DMAResource::Init(device_node* node, size_t blockSize, uint32 bufferCount)
|
||||
|
||||
uint32 value;
|
||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
||||
B_BLOCK_DEVICE_DMA_ALIGNMENT, &value, true) == B_OK)
|
||||
B_DMA_ALIGNMENT, &value, true) == B_OK)
|
||||
restrictions.alignment = value + 1;
|
||||
|
||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
||||
B_BLOCK_DEVICE_DMA_BOUNDARY, &value, true) == B_OK)
|
||||
B_DMA_BOUNDARY, &value, true) == B_OK)
|
||||
restrictions.boundary = value + 1;
|
||||
|
||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
||||
B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, &value, true) == B_OK)
|
||||
restrictions.max_segment_size = value;
|
||||
B_DMA_MAX_SEGMENT_BLOCKS, &value, true) == B_OK)
|
||||
restrictions.max_segment_size = value * blockSize;
|
||||
|
||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
||||
B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &value, true) == B_OK)
|
||||
B_DMA_MAX_TRANSFER_BLOCKS, &value, true) == B_OK)
|
||||
restrictions.max_transfer_size = value * blockSize;
|
||||
|
||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
||||
B_BLOCK_DEVICE_MAX_SG_BLOCKS, &value, true) == B_OK)
|
||||
B_DMA_MAX_SEGMENT_COUNT, &value, true) == B_OK)
|
||||
restrictions.max_segment_count = value;
|
||||
|
||||
return Init(restrictions, blockSize, bufferCount);
|
||||
|
||||
Reference in New Issue
Block a user