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