Added raw SCSI bus driver (from Thomas Kurschel).
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7770 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
SubDir OBOS_TOP src add-ons kernel drivers bus ;
|
||||
|
||||
SubInclude OBOS_TOP src add-ons kernel drivers bus scsi ;
|
||||
@@ -0,0 +1,8 @@
|
||||
SubDir OBOS_TOP src add-ons kernel drivers bus scsi ;
|
||||
|
||||
UsePrivateHeaders kernel ;
|
||||
|
||||
KernelAddon scsi_raw : kernel drivers bus scsi :
|
||||
scsi_raw.c
|
||||
;
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Part of Open SCSI raw driver.
|
||||
|
||||
We don't support particular file handles, instead we use
|
||||
file handle = device handle.
|
||||
*/
|
||||
|
||||
|
||||
#include "scsi_raw.h"
|
||||
#include <string.h>
|
||||
#include <scsi.h>
|
||||
#include <malloc.h>
|
||||
#include <pnp_devfs.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
device_manager_info *pnp;
|
||||
|
||||
|
||||
static status_t
|
||||
raw_open(void *device_cookie, uint32 flags, void **handle_cookie)
|
||||
{
|
||||
*handle_cookie = device_cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
raw_close(void *cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
raw_free(void *cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static status_t
|
||||
raw_control(void *cookie, uint32 op, void *data, size_t len)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static status_t
|
||||
raw_read(void *cookie, off_t position, void *data, size_t *numBytes)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
raw_write(void *cookie, off_t position, const void *data, size_t *numBytes)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/** !!!keep this in sync with scsi_periph module!!! */
|
||||
|
||||
static status_t
|
||||
raw_command(raw_device_info *device, raw_device_command *cmd)
|
||||
{
|
||||
scsi_ccb *request;
|
||||
|
||||
SHOW_FLOW0(3, "");
|
||||
|
||||
request = device->scsi->alloc_ccb(device->scsi_device);
|
||||
if (request == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
request->flags = 0;
|
||||
|
||||
if (cmd->flags & B_RAW_DEVICE_DATA_IN)
|
||||
request->flags |= SCSI_DIR_IN;
|
||||
else
|
||||
request->flags |= SCSI_DIR_OUT;
|
||||
|
||||
request->data = cmd->data;
|
||||
request->sg_list = NULL;
|
||||
request->data_len = cmd->data_length;
|
||||
request->sort = -1;
|
||||
request->timeout = cmd->timeout;
|
||||
|
||||
memcpy( request->cdb, cmd->command, SCSI_MAX_CDB_SIZE );
|
||||
request->cdb_len = cmd->command_length;
|
||||
|
||||
device->scsi->sync_io( request );
|
||||
|
||||
// TBD: should we call standard error handler here, or may the
|
||||
// actions done there (like starting the unit) confuse the application?
|
||||
|
||||
cmd->cam_status = request->subsys_status;
|
||||
cmd->scsi_status = request->device_status;
|
||||
|
||||
if( (request->subsys_status & SCSI_AUTOSNS_VALID) != 0 && cmd->sense_data ) {
|
||||
memcpy( cmd->sense_data, request->sense,
|
||||
min( cmd->sense_data_length, SCSI_MAX_SENSE_SIZE - request->sense_resid ));
|
||||
}
|
||||
|
||||
if( (cmd->flags & B_RAW_DEVICE_REPORT_RESIDUAL) != 0 ) {
|
||||
// this is a bit strange, see Be's sample code where I pinched this from;
|
||||
// normally, residual means "number of unused bytes left"
|
||||
// but here, we have to return "number of used bytes", which is the opposite
|
||||
cmd->data_length = cmd->data_length - request->data_resid;
|
||||
cmd->sense_data_length = SCSI_MAX_SENSE_SIZE - request->sense_resid;
|
||||
}
|
||||
|
||||
device->scsi->free_ccb( request );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
raw_ioctl(raw_device_info *device, int op, void *buf, size_t len)
|
||||
{
|
||||
status_t res;
|
||||
|
||||
switch( op ) {
|
||||
case B_RAW_DEVICE_COMMAND:
|
||||
res = raw_command( device, buf );
|
||||
// __asm( "int $3" : : );
|
||||
break;
|
||||
|
||||
default:
|
||||
res = B_DEV_INVALID_IOCTL;
|
||||
}
|
||||
|
||||
SHOW_FLOW( 4, "%x: %s", op, strerror( res ));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
raw_init_device(pnp_node_handle node, void *user_cookie, void **cookie)
|
||||
{
|
||||
raw_device_info *device;
|
||||
status_t res;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
device = (raw_device_info *)calloc( 1, sizeof( *device ));
|
||||
if( device == NULL )
|
||||
return B_NO_MEMORY;
|
||||
|
||||
device->node = node;
|
||||
|
||||
// register it everywhere
|
||||
res = pnp->load_driver( pnp->get_parent( node ), NULL,
|
||||
(pnp_driver_info **)&device->scsi, (void **)&device->scsi_device );
|
||||
if( res != B_OK )
|
||||
goto err;
|
||||
|
||||
SHOW_FLOW0( 3, "done" );
|
||||
|
||||
*cookie = device;
|
||||
return B_OK;
|
||||
|
||||
err:
|
||||
free( device );
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
raw_uninit_device(raw_device_info *device)
|
||||
{
|
||||
pnp->unload_driver(pnp->get_parent(device->node));
|
||||
free(device);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/** called whenever a new SCSI device was added to system;
|
||||
* we register a devfs entry for every device
|
||||
*/
|
||||
|
||||
static status_t
|
||||
raw_device_added(pnp_node_handle node)
|
||||
{
|
||||
char *str;
|
||||
uint8 path_id, target_id, target_lun;
|
||||
char name[100];
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
// make sure we can handle this parent device
|
||||
if( pnp->get_attr_string( node, PNP_DRIVER_TYPE, &str, false ) != B_OK )
|
||||
return B_ERROR;
|
||||
|
||||
if( strcmp( str, SCSI_DEVICE_TYPE_NAME ) != 0 ) {
|
||||
free( str );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
free( str );
|
||||
|
||||
// compose name
|
||||
if( pnp->get_attr_uint8( node,
|
||||
SCSI_BUS_PATH_ID_ITEM, &path_id, true ) != B_OK ||
|
||||
pnp->get_attr_uint8( node,
|
||||
SCSI_DEVICE_TARGET_ID_ITEM, &target_id, true ) != B_OK ||
|
||||
pnp->get_attr_uint8( node,
|
||||
SCSI_DEVICE_TARGET_LUN_ITEM, &target_lun, true ) != B_OK )
|
||||
return B_ERROR;
|
||||
|
||||
sprintf( name, "bus/scsi/%d/%d/%d/raw",
|
||||
path_id, target_id, target_lun );
|
||||
|
||||
SHOW_FLOW( 3, "name=%s", name );
|
||||
|
||||
// ready to register
|
||||
{
|
||||
pnp_node_attr attrs[] =
|
||||
{
|
||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_RAW_MODULE_NAME }},
|
||||
|
||||
// default connection is used by peripheral drivers, and as we don't
|
||||
// want to kick them out, we use concurrent "raw" connection
|
||||
// (btw: this shows nicely that something goes wrong: one device
|
||||
// and two drivers means begging for trouble)
|
||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "raw" }},
|
||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "raw" }},
|
||||
|
||||
// we want devfs on top of us
|
||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
|
||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
||||
// tell which name we want to have in devfs
|
||||
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return pnp->register_device( node, attrs, NULL, &node );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
std_ops(int32 op, ...)
|
||||
{
|
||||
switch (op) {
|
||||
case B_MODULE_INIT:
|
||||
case B_MODULE_UNINIT:
|
||||
return B_OK;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module_dependency module_dependencies[] = {
|
||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||
{}
|
||||
};
|
||||
|
||||
pnp_devfs_driver_info scsi_raw_module = {
|
||||
{
|
||||
{
|
||||
SCSI_RAW_MODULE_NAME,
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
|
||||
raw_init_device,
|
||||
(status_t (*) (void *))raw_uninit_device,
|
||||
raw_device_added,
|
||||
NULL
|
||||
},
|
||||
|
||||
(status_t (*)( void *, uint32, void ** )) &raw_open,
|
||||
raw_close,
|
||||
raw_free,
|
||||
(status_t (*)( void *, uint32, void *, size_t )) &raw_ioctl,
|
||||
|
||||
raw_read,
|
||||
raw_write,
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
#if !_BUILDING_kernel && !BOOT
|
||||
_EXPORT
|
||||
module_info *modules[] =
|
||||
{
|
||||
(module_info *)&scsi_raw_module,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
** Copyright 2003, Thomas Kurschel. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Part of Open SCSI Raw Driver
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_RAW_H
|
||||
#define _SCSI_RAW_H
|
||||
|
||||
#include <device_manager.h>
|
||||
#include <bus/SCSI.h>
|
||||
|
||||
#define debug_level_flow 0
|
||||
#define debug_level_error 3
|
||||
#define debug_level_info 0
|
||||
|
||||
#define DEBUG_MSG_PREFIX "SCSI_RAW -- "
|
||||
|
||||
#include "wrapper.h"
|
||||
|
||||
|
||||
typedef struct raw_device_info {
|
||||
pnp_node_handle node;
|
||||
scsi_device scsi_device;
|
||||
scsi_device_interface *scsi;
|
||||
} raw_device_info;
|
||||
|
||||
|
||||
#define SCSI_RAW_MODULE_NAME "drivers/bus/scsi/scsi_raw/"SCSI_DEVICE_TYPE_NAME
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
#ifndef _WRAPPER_H
|
||||
#define _WRAPPER_H
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <lock.h>
|
||||
|
||||
|
||||
// benaphores
|
||||
|
||||
#define INIT_BEN(x, prefix) benaphore_init(x, prefix)
|
||||
#define DELETE_BEN(x) benaphore_destroy(x)
|
||||
#define ACQUIRE_BEN(x) benaphore_lock(x)
|
||||
#define RELEASE_BEN(x) benaphore_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 3
|
||||
#endif
|
||||
|
||||
#ifndef debug_level_info
|
||||
# define debug_level_info 2
|
||||
#endif
|
||||
|
||||
#ifndef debug_level_error
|
||||
# define debug_level_error 1
|
||||
#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"##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"##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"##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"##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"##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"##format"\n", FUNC_NAME); DEBUG_WAIT_ERROR \
|
||||
}} while( 0 )
|
||||
|
||||
#endif /* _BENAPHORE_H */
|
||||
Reference in New Issue
Block a user