* 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_FIND_MULTIPLE_CHILDREN 0x02
|
||||||
#define B_KEEP_DRIVER_LOADED 0x04
|
#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 */
|
/* 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.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
*
|
*
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <bus/SCSI.h>
|
#include <bus/SCSI.h>
|
||||||
#include <block_io.h>
|
|
||||||
#include <scsi_cmds.h>
|
#include <scsi_cmds.h>
|
||||||
#include <Drivers.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 agp_gart ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers config_manager ;
|
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 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 ide ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers isa ;
|
SubInclude HAIKU_TOP src add-ons kernel bus_managers isa ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers pci ;
|
SubInclude HAIKU_TOP src add-ons kernel bus_managers pci ;
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
#include <block_io.h>
|
|
||||||
|
|
||||||
#define TRACE dprintf
|
#define TRACE dprintf
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +28,7 @@ ide_channel_added(device_node *parent)
|
|||||||
|
|
||||||
TRACE("ide_channel_added, parent is %p\n", 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) {
|
&controller_name, true) != B_OK) {
|
||||||
dprintf("ide: ignored controller - controller name missing\n");
|
dprintf("ide: ignored controller - controller name missing\n");
|
||||||
goto err;
|
goto err;
|
||||||
@@ -61,7 +59,7 @@ ide_channel_added(device_node *parent)
|
|||||||
// which should be sufficient)
|
// which should be sufficient)
|
||||||
// Note: to fix specific drive bugs, use ide_sim_get_restrictions()
|
// Note: to fix specific drive bugs, use ide_sim_get_restrictions()
|
||||||
// in ide_sim.c!
|
// 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 }},
|
{ IDE_CHANNEL_ID_ITEM, B_UINT32_TYPE, { ui32: channel_id }},
|
||||||
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: IDE_CHANNEL_ID_GENERATOR }},
|
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: IDE_CHANNEL_ID_GENERATOR }},
|
||||||
// { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: channel_id }},
|
// { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: channel_id }},
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
#include <block_io.h>
|
|
||||||
|
|
||||||
|
|
||||||
/** called when an IDE channel was registered by a controller driver */
|
/** 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)
|
// which should be sufficient)
|
||||||
// Note: to fix specific drive bugs, use ide_sim_get_restrictions()
|
// Note: to fix specific drive bugs, use ide_sim_get_restrictions()
|
||||||
// in ide_sim.c!
|
// 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 }},
|
{ IDE_CHANNEL_ID_ITEM, B_UINT32_TYPE, { ui32: channel_id }},
|
||||||
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: IDE_CHANNEL_ID_GENERATOR }},
|
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: IDE_CHANNEL_ID_GENERATOR }},
|
||||||
// { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: channel_id }},
|
// { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: channel_id }},
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <block_io.h>
|
|
||||||
|
|
||||||
|
|
||||||
// bus service should hurry up a bit - good controllers don't take much time
|
// 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;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
// extract controller/protocoll restrictions from node
|
// 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;
|
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;
|
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;
|
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;
|
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;
|
bus->dma_params.max_sg_blocks = ~0;
|
||||||
|
|
||||||
// do some sanity check:
|
// do some sanity check:
|
||||||
// (see blkman.c)
|
|
||||||
bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment;
|
bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment;
|
||||||
|
|
||||||
if (bus->dma_params.alignment > B_PAGE_SIZE) {
|
if (bus->dma_params.alignment > B_PAGE_SIZE) {
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
#include "scsi_internal.h"
|
#include "scsi_internal.h"
|
||||||
|
|
||||||
#include <block_io.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -103,7 +101,8 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
|
|||||||
// find maximum transfer blocks
|
// find maximum transfer blocks
|
||||||
// set default value to max (need something like ULONG_MAX here)
|
// set default value to max (need something like ULONG_MAX here)
|
||||||
orig_max_blocks = ~0;
|
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);
|
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" }},
|
{ B_DEVICE_BUS, B_STRING_TYPE, { string: "scsi" }},
|
||||||
|
|
||||||
// extra restriction of maximum number of blocks per transfer
|
// 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
|
// atapi emulation
|
||||||
{ SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }},
|
{ SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }},
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#include <bus/IDE.h>
|
#include <bus/IDE.h>
|
||||||
#include <ide_types.h>
|
#include <ide_types.h>
|
||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
#include <block_io.h>
|
|
||||||
|
|
||||||
|
|
||||||
//#define TRACE_IDE_ISA
|
//#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
|
// DMA properties; the 16 bit alignment is not necessary as
|
||||||
// the ide bus manager handles that very efficiently, but why
|
// the ide bus manager handles that very efficiently, but why
|
||||||
// not use the block device manager for doing that?
|
// 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
|
// private data to identify device
|
||||||
{ IDE_ISA_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }},
|
{ IDE_ISA_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }},
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
#include <bus/IDE.h>
|
#include <bus/IDE.h>
|
||||||
#include <ide_adapter.h>
|
#include <ide_adapter.h>
|
||||||
#include <block_io.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define DRIVER_PRETTY_NAME "Legacy SATA"
|
#define DRIVER_PRETTY_NAME "Legacy SATA"
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <bus/ide/ide_adapter.h>
|
#include <bus/ide/ide_adapter.h>
|
||||||
#include <block_io.h>
|
|
||||||
|
|
||||||
#define debug_level_flow 0
|
#define debug_level_flow 0
|
||||||
#define debug_level_error 3
|
#define debug_level_error 3
|
||||||
@@ -95,7 +94,7 @@ inthand(void *arg)
|
|||||||
if (channel->dmaing) {
|
if (channel->dmaing) {
|
||||||
// in DMA mode, there is a safe test
|
// in DMA mode, there is a safe test
|
||||||
// in PIO mode, this doesn't work
|
// 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 );
|
channel->bus_master_base + ide_bm_status_reg );
|
||||||
|
|
||||||
if (!bm_status.interrupt)
|
if (!bm_status.interrupt)
|
||||||
@@ -179,7 +178,7 @@ controller_removed(device_node_handle node, ide_adapter_controller_info *control
|
|||||||
// publish node of ide controller
|
// publish node of ide controller
|
||||||
|
|
||||||
static status_t
|
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)
|
io_resource_handle *resources, device_node_handle *node)
|
||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
@@ -199,13 +198,13 @@ publish_controller(device_node_handle parent, uint16 bus_master_base, uint8 intn
|
|||||||
// DMA properties
|
// DMA properties
|
||||||
// some say it must be dword-aligned, others that it can be byte-aligned;
|
// some say it must be dword-aligned, others that it can be byte-aligned;
|
||||||
// stay on the safe side
|
// 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
|
// 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
|
// size of S/G block is 16 bits with zero being 64K
|
||||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE, { ui32: 0x10000 }},
|
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { ui32: 0x10000 }},
|
||||||
// see definition of MAX_SG_COUNT
|
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
||||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE, { ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
{ ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
||||||
|
|
||||||
// private data to find controller
|
// private data to find controller
|
||||||
{ IDE_ADAPTER_BUS_MASTER_BASE, B_UINT16_TYPE, { ui16: bus_master_base }},
|
{ 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);
|
return publish_controller(parent, bus_master_base, intnum, resource_handles, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
probe_controller(device_node_handle parent)
|
probe_controller(device_node_handle parent)
|
||||||
{
|
{
|
||||||
@@ -284,14 +283,14 @@ probe_controller(device_node_handle parent)
|
|||||||
if (res != B_OK || controller_node == NULL)
|
if (res != B_OK || controller_node == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
ide_adapter->detect_channel(pci, device, controller_node,
|
ide_adapter->detect_channel(pci, device, controller_node,
|
||||||
PROMISE_TX2_CHANNEL_MODULE_NAME, true,
|
PROMISE_TX2_CHANNEL_MODULE_NAME, true,
|
||||||
command_block_base[0], control_block_base[0], bus_master_base, intnum,
|
command_block_base[0], control_block_base[0], bus_master_base, intnum,
|
||||||
0, "Primary Channel", &channels[0], false);
|
0, "Primary Channel", &channels[0], false);
|
||||||
|
|
||||||
ide_adapter->detect_channel(pci, device, controller_node,
|
ide_adapter->detect_channel(pci, device, controller_node,
|
||||||
PROMISE_TX2_CHANNEL_MODULE_NAME, true,
|
PROMISE_TX2_CHANNEL_MODULE_NAME, true,
|
||||||
command_block_base[1], control_block_base[1], bus_master_base, intnum,
|
command_block_base[1], control_block_base[1], bus_master_base, intnum,
|
||||||
1, "Secondary Channel", &channels[1], false);
|
1, "Secondary Channel", &channels[1], false);
|
||||||
|
|
||||||
pnp->uninit_driver(parent);
|
pnp->uninit_driver(parent);
|
||||||
@@ -299,7 +298,7 @@ probe_controller(device_node_handle parent)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
pnp->uninit_driver(parent);
|
pnp->uninit_driver(parent);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <bus/IDE.h>
|
#include <bus/IDE.h>
|
||||||
|
|
||||||
#include <ide_adapter.h>
|
#include <ide_adapter.h>
|
||||||
#include <block_io.h>
|
|
||||||
|
|
||||||
#define TRACE(x...) dprintf("si-3112: " x)
|
#define TRACE(x...) dprintf("si-3112: " x)
|
||||||
//#define FLOW(x...) dprintf("si-3112: " x)
|
//#define FLOW(x...) dprintf("si-3112: " x)
|
||||||
@@ -225,13 +224,13 @@ controller_probe(device_node *parent)
|
|||||||
// DMA properties
|
// DMA properties
|
||||||
// data must be word-aligned;
|
// data must be word-aligned;
|
||||||
// warning: some controllers are more picky!
|
// 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
|
// 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
|
// 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 }},
|
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { ui32: 0x10000 }},
|
||||||
// see definition of MAX_SG_COUNT
|
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
||||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE, { ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
{ ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
||||||
|
|
||||||
// private data to find controller
|
// private data to find controller
|
||||||
{ "silicon_image_3112/asic_index", B_UINT32_TYPE, { ui32: asicIndex }},
|
{ "silicon_image_3112/asic_index", B_UINT32_TYPE, { ui32: asicIndex }},
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <block_io.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define TRACE(a...) dprintf("\33[35mahci:\33[0m " a)
|
#define TRACE(a...) dprintf("\33[35mahci:\33[0m " a)
|
||||||
#define FLOW(a...) dprintf("ahci: " a)
|
#define FLOW(a...) dprintf("ahci: " a)
|
||||||
@@ -148,7 +146,7 @@ register_sim(device_node *parent)
|
|||||||
|
|
||||||
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
|
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
|
||||||
{ string: AHCI_DEVICE_MODULE_NAME }},
|
{ 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 }},
|
{ AHCI_ID_ITEM, B_UINT32_TYPE, { ui32: id }},
|
||||||
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE,
|
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE,
|
||||||
// { string: AHCI_ID_GENERATOR }},
|
// { string: AHCI_ID_GENERATOR }},
|
||||||
@@ -237,16 +235,12 @@ ahci_register_device(device_node *parent)
|
|||||||
|
|
||||||
// DMA properties
|
// DMA properties
|
||||||
// data must be word-aligned;
|
// data must be word-aligned;
|
||||||
{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE,
|
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1 }},
|
||||||
{ ui32: 1 }},
|
|
||||||
// one S/G block must not cross 64K boundary
|
// one S/G block must not cross 64K boundary
|
||||||
{ B_BLOCK_DEVICE_DMA_BOUNDARY, B_UINT32_TYPE,
|
{ B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
|
||||||
{ ui32: 0xffff }},
|
|
||||||
// max size of S/G block is 16 bits with zero being 64K
|
// max size of S/G block is 16 bits with zero being 64K
|
||||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE,
|
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { ui32: 0x10000 }},
|
||||||
{ ui32: 0x10000 }},
|
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
||||||
// see definition of MAX_SG_COUNT
|
|
||||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE,
|
|
||||||
{ ui32: 32 /* whatever... */ }},
|
{ ui32: 32 /* whatever... */ }},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -674,7 +674,7 @@ cd_write(void* cookie, off_t pos, const void* buffer, size_t* _length)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
cd_io(void *cookie, io_request *request)
|
cd_io(void* cookie, io_request* request)
|
||||||
{
|
{
|
||||||
cd_handle* handle = (cd_handle*)cookie;
|
cd_handle* handle = (cd_handle*)cookie;
|
||||||
|
|
||||||
@@ -797,7 +797,7 @@ cd_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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",
|
TRACE("cd_set_capacity(info = %p, capacity = %Ld, blockSize = %ld)\n",
|
||||||
info, capacity, blockSize);
|
info, capacity, blockSize);
|
||||||
@@ -838,7 +838,7 @@ cd_set_capacity(cd_driver_info *info, uint64 capacity, uint32 blockSize)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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
|
// do a capacity check
|
||||||
// TBD: is this a good idea (e.g. if this is an empty CD)?
|
// TBD: is this a good idea (e.g. if this is an empty CD)?
|
||||||
@@ -856,9 +856,9 @@ scsi_periph_callbacks callbacks = {
|
|||||||
|
|
||||||
|
|
||||||
static float
|
static float
|
||||||
cd_supports_device(device_node *parent)
|
cd_supports_device(device_node* parent)
|
||||||
{
|
{
|
||||||
const char *bus;
|
const char* bus;
|
||||||
uint8 deviceType;
|
uint8 deviceType;
|
||||||
|
|
||||||
// make sure parent is really the SCSI bus manager
|
// 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
|
server by the block_io module
|
||||||
*/
|
*/
|
||||||
static status_t
|
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;
|
size_t inquiryLength;
|
||||||
uint32 maxBlocks;
|
uint32 maxBlocks;
|
||||||
|
|
||||||
// get inquiry data
|
// get inquiry data
|
||||||
if (sDeviceManager->get_attr_raw(node, SCSI_DEVICE_INQUIRY_ITEM,
|
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))
|
|| inquiryLength < sizeof(deviceInquiry))
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
// get block limit of underlying hardware to lower it (if necessary)
|
// 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, true) != B_OK)
|
||||||
maxBlocks = INT_MAX;
|
maxBlocks = INT_MAX;
|
||||||
|
|
||||||
@@ -907,10 +907,8 @@ cd_register_device(device_node *node)
|
|||||||
|
|
||||||
// ready to register
|
// ready to register
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
// tell block_io whether the device is removable
|
|
||||||
{"removable", B_UINT8_TYPE, {ui8: deviceInquiry->removable_medium}},
|
{"removable", B_UINT8_TYPE, {ui8: deviceInquiry->removable_medium}},
|
||||||
// impose own max block restriction
|
{B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, {ui32: maxBlocks}},
|
||||||
{B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, {ui32: maxBlocks}},
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -920,24 +918,21 @@ cd_register_device(device_node *node)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
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");
|
TRACE("cd_init_driver");
|
||||||
|
|
||||||
status = sDeviceManager->get_attr_uint8(node, "removable",
|
uint8 removable;
|
||||||
|
status_t status = sDeviceManager->get_attr_uint8(node, "removable",
|
||||||
&removable, false);
|
&removable, false);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
info = (cd_driver_info *)malloc(sizeof(*info));
|
cd_driver_info* info = (cd_driver_info*)malloc(sizeof(cd_driver_info));
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
memset(info, 0, sizeof(*info));
|
memset(info, 0, sizeof(cd_driver_info));
|
||||||
|
|
||||||
info->dma_resource = new(std::nothrow) DMAResource;
|
info->dma_resource = new(std::nothrow) DMAResource;
|
||||||
if (info->dma_resource == NULL) {
|
if (info->dma_resource == NULL) {
|
||||||
@@ -956,8 +951,8 @@ cd_init_driver(device_node *node, void **cookie)
|
|||||||
&info->device_type, true);
|
&info->device_type, true);
|
||||||
|
|
||||||
device_node *parent = sDeviceManager->get_parent_node(node);
|
device_node *parent = sDeviceManager->get_parent_node(node);
|
||||||
sDeviceManager->get_driver(parent, (driver_module_info **)&info->scsi,
|
sDeviceManager->get_driver(parent, (driver_module_info**)&info->scsi,
|
||||||
(void **)&info->scsi_device);
|
(void**)&info->scsi_device);
|
||||||
sDeviceManager->put_node(parent);
|
sDeviceManager->put_node(parent);
|
||||||
|
|
||||||
status = sSCSIPeripheral->register_device((periph_device_cookie)info,
|
status = sSCSIPeripheral->register_device((periph_device_cookie)info,
|
||||||
@@ -968,15 +963,15 @@ cd_init_driver(device_node *node, void **cookie)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
*cookie = info;
|
*_cookie = info;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
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);
|
sSCSIPeripheral->unregister_device(info->scsi_periph_device);
|
||||||
free(info);
|
free(info);
|
||||||
@@ -984,17 +979,15 @@ cd_uninit_driver(void *_cookie)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
cd_register_child_devices(void *_cookie)
|
cd_register_child_devices(void* _cookie)
|
||||||
{
|
{
|
||||||
cd_driver_info *info = (cd_driver_info *)_cookie;
|
cd_driver_info* info = (cd_driver_info*)_cookie;
|
||||||
status_t status;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
name = sSCSIPeripheral->compose_device_name(info->node, "disk/scsi");
|
char* name = sSCSIPeripheral->compose_device_name(info->node, "disk/scsi");
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
status = sDeviceManager->publish_device(info->node, name,
|
status_t status = sDeviceManager->publish_device(info->node, name,
|
||||||
SCSI_CD_DEVICE_MODULE_NAME);
|
SCSI_CD_DEVICE_MODULE_NAME);
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#define _SCSI_CD_H
|
#define _SCSI_CD_H
|
||||||
|
|
||||||
|
|
||||||
#include <block_io.h>
|
|
||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
#include <scsi_periph.h>
|
#include <scsi_periph.h>
|
||||||
#include <scsi.h>
|
#include <scsi.h>
|
||||||
|
|||||||
@@ -441,7 +441,7 @@ das_register_device(device_node *node)
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
// get block limit of underlying hardware to lower it (if necessary)
|
// 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, true) != B_OK)
|
||||||
maxBlocks = INT_MAX;
|
maxBlocks = INT_MAX;
|
||||||
|
|
||||||
@@ -455,7 +455,7 @@ das_register_device(device_node *node)
|
|||||||
// tell block_io whether the device is removable
|
// tell block_io whether the device is removable
|
||||||
{"removable", B_UINT8_TYPE, {ui8: deviceInquiry->removable_medium}},
|
{"removable", B_UINT8_TYPE, {ui8: deviceInquiry->removable_medium}},
|
||||||
// impose own max block restriction
|
// 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 }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#define _SCSI_DISK_H
|
#define _SCSI_DISK_H
|
||||||
|
|
||||||
|
|
||||||
#include <block_io.h>
|
|
||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
#include <scsi.h>
|
#include <scsi.h>
|
||||||
#include <scsi_periph.h>
|
#include <scsi_periph.h>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel generic ;
|
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 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 dpc ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ;
|
SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ;
|
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 <bus/IDE.h>
|
||||||
#include <ide_types.h>
|
#include <ide_types.h>
|
||||||
#include <ide_adapter.h>
|
#include <ide_adapter.h>
|
||||||
#include <block_io.h>
|
|
||||||
#include <lendian_bitfield.h>
|
#include <lendian_bitfield.h>
|
||||||
|
|
||||||
#define debug_level_flow 0
|
#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)
|
// command queuing always works (unless controller is buggy)
|
||||||
{ IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: can_cq }},
|
{ IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: can_cq }},
|
||||||
// choose any name here
|
// 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
|
// DMA properties
|
||||||
// data must be word-aligned;
|
// data must be word-aligned;
|
||||||
// warning: some controllers are more picky!
|
// 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
|
// 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
|
// 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*/ }},
|
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE,
|
||||||
// see definition of MAX_SG_COUNT
|
{ ui32: max_sg_block_size/*0x10000*/ }},
|
||||||
{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE, { ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
||||||
|
{ ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
||||||
|
|
||||||
// private data to find controller
|
// private data to find controller
|
||||||
{ IDE_ADAPTER_BUS_MASTER_BASE, B_UINT16_TYPE, { ui16: bus_master_base }},
|
{ IDE_ADAPTER_BUS_MASTER_BASE, B_UINT16_TYPE, { ui16: bus_master_base }},
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include <scsi_periph.h>
|
#include <scsi_periph.h>
|
||||||
#include <block_io.h>
|
|
||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
|
|
||||||
#include "io_requests.h"
|
#include "io_requests.h"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include "dma_resources.h"
|
#include "dma_resources.h"
|
||||||
|
|
||||||
#include <block_io.h>
|
#include <device_manager.h>
|
||||||
|
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
@@ -124,23 +124,23 @@ DMAResource::Init(device_node* node, size_t blockSize, uint32 bufferCount)
|
|||||||
|
|
||||||
uint32 value;
|
uint32 value;
|
||||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
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;
|
restrictions.alignment = value + 1;
|
||||||
|
|
||||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
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;
|
restrictions.boundary = value + 1;
|
||||||
|
|
||||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
if (gDeviceManagerModule.get_attr_uint32(node,
|
||||||
B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, &value, true) == B_OK)
|
B_DMA_MAX_SEGMENT_BLOCKS, &value, true) == B_OK)
|
||||||
restrictions.max_segment_size = value;
|
restrictions.max_segment_size = value * blockSize;
|
||||||
|
|
||||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
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;
|
restrictions.max_transfer_size = value * blockSize;
|
||||||
|
|
||||||
if (gDeviceManagerModule.get_attr_uint32(node,
|
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;
|
restrictions.max_segment_count = value;
|
||||||
|
|
||||||
return Init(restrictions, blockSize, bufferCount);
|
return Init(restrictions, blockSize, bufferCount);
|
||||||
|
|||||||
Reference in New Issue
Block a user