diff --git a/src/add-ons/kernel/drivers/bus/Jamfile b/src/add-ons/kernel/drivers/bus/Jamfile new file mode 100644 index 0000000000..105977ee09 --- /dev/null +++ b/src/add-ons/kernel/drivers/bus/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP src add-ons kernel drivers bus ; + +SubInclude OBOS_TOP src add-ons kernel drivers bus scsi ; diff --git a/src/add-ons/kernel/drivers/bus/scsi/Jamfile b/src/add-ons/kernel/drivers/bus/scsi/Jamfile new file mode 100644 index 0000000000..dfe2164acf --- /dev/null +++ b/src/add-ons/kernel/drivers/bus/scsi/Jamfile @@ -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 + ; + diff --git a/src/add-ons/kernel/drivers/bus/scsi/scsi_raw.c b/src/add-ons/kernel/drivers/bus/scsi/scsi_raw.c new file mode 100644 index 0000000000..cebee96554 --- /dev/null +++ b/src/add-ons/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 +#include +#include +#include +#include + + +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 diff --git a/src/add-ons/kernel/drivers/bus/scsi/scsi_raw.h b/src/add-ons/kernel/drivers/bus/scsi/scsi_raw.h new file mode 100644 index 0000000000..c24b1f2607 --- /dev/null +++ b/src/add-ons/kernel/drivers/bus/scsi/scsi_raw.h @@ -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 +#include + +#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 diff --git a/src/add-ons/kernel/drivers/bus/scsi/wrapper.h b/src/add-ons/kernel/drivers/bus/scsi/wrapper.h new file mode 100644 index 0000000000..6793cb73be --- /dev/null +++ b/src/add-ons/kernel/drivers/bus/scsi/wrapper.h @@ -0,0 +1,89 @@ +#ifndef _WRAPPER_H +#define _WRAPPER_H + +#include +#include + + +// 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 */