* 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:
Axel Dörfler
2008-08-14 15:08:16 +00:00
parent 61b1a536e8
commit 70e2d4ac43
29 changed files with 91 additions and 1904 deletions
-102
View File
@@ -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__ */
+8
View File
@@ -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 -2
View File
@@ -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>
+1
View File
@@ -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 }},
+10 -7
View File
@@ -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 }},
+5 -11
View File
@@ -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
View File
@@ -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, &params.alignment, true) != B_OK)
params.alignment = 0;
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &params.max_blocks, true) != B_OK)
params.max_blocks = 0xffffffff;
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_DMA_BOUNDARY, &params.dma_boundary, true) != B_OK)
params.dma_boundary = ~0;
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, &params.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, &params.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);
-740
View File
@@ -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);