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:
Axel Dörfler
2004-06-07 00:00:30 +00:00
parent 0d59a3d2a9
commit c8bbe37502
5 changed files with 441 additions and 0 deletions
+3
View File
@@ -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 */