Author: bonefish Date: 2011-01-08 20:29:20 +0100 (Sat, 08 Jan 2011) New Revision: 40163 Changeset: http://dev.haiku-os.org/changeset/40163 Added: haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/bus_raw.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/busses.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/ccb.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/device_scan.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/devices.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/dpc.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/queuing.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/scatter_gather.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/scsi.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/scsi_io.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/sim_interface.cpp haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/virtual_memory.cpp Removed: haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/bus_raw.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/busses.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/ccb.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/device_scan.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/devices.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/dpc.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/queuing.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/scatter_gather.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/scsi.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/scsi_io.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/sim_interface.c haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/virtual_memory.c Modified: haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/Jamfile Log: *.c -> *.cpp (includes private kernel headers). Modified: haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/Jamfile =================================================================== --- haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/Jamfile 2011-01-08 19:14:49 UTC (rev 40162) +++ haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/Jamfile 2011-01-08 19:29:20 UTC (rev 40163) @@ -10,19 +10,19 @@ } KernelAddon scsi : - bus_raw.c - busses.c - ccb.c - device_scan.c - devices.c + bus_raw.cpp + busses.cpp + ccb.cpp + device_scan.cpp + devices.cpp dma_buffer.cpp - dpc.c + dpc.cpp emulation.cpp - queuing.c - scsi.c - scsi_io.c - scatter_gather.c - sim_interface.c - virtual_memory.c + queuing.cpp + scsi.cpp + scsi_io.cpp + scatter_gather.cpp + sim_interface.cpp + virtual_memory.cpp ; Copied: haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/bus_raw.cpp (from rev 40148, haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/bus_raw.c) =================================================================== --- haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/bus_raw.cpp (rev 0) +++ haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/bus_raw.cpp 2011-01-08 19:29:20 UTC (rev 40163) @@ -0,0 +1,137 @@ +/* + * Copyright 2002-04, Thomas Kurschel. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +//! Devfs entry for raw bus access. + + +#include "scsi_internal.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <device/scsi_bus_raw_driver.h> + + +// info about bus +// (used both as bus cookie and file handle cookie) +typedef struct bus_raw_info { + scsi_bus_interface *interface; + scsi_bus cookie; + device_node *node; +} bus_raw_info; + + +static status_t +scsi_bus_raw_init(void *driverCookie, void **_cookie) +{ + device_node *node = (device_node *)driverCookie; + device_node *parent; + bus_raw_info *bus; + + bus = (bus_raw_info*)malloc(sizeof(*bus)); + if (bus == NULL) + return B_NO_MEMORY; + + parent = pnp->get_parent_node(node); + pnp->get_driver(parent, + (driver_module_info **)&bus->interface, (void **)&bus->cookie); + pnp->put_node(parent); + + bus->node = node; + + *_cookie = bus; + return B_OK; +} + + +static void +scsi_bus_raw_uninit(void *bus) +{ + free(bus); +} + + +static status_t +scsi_bus_raw_open(void *bus, const char *path, int openMode, + void **handle_cookie) +{ + *handle_cookie = bus; + return B_OK; +} + + +static status_t +scsi_bus_raw_close(void *cookie) +{ + return B_OK; +} + + +static status_t +scsi_bus_raw_free(void *cookie) +{ + return B_OK; +} + + +static status_t +scsi_bus_raw_control(void *_cookie, uint32 op, void *data, size_t length) +{ + bus_raw_info *bus = (bus_raw_info*)_cookie; + + switch (op) { + case B_SCSI_BUS_RAW_RESET: + return bus->interface->reset_bus(bus->cookie); + + case B_SCSI_BUS_RAW_PATH_INQUIRY: + return bus->interface->path_inquiry(bus->cookie, + (scsi_path_inquiry*)data); + } + + return B_ERROR; +} + + +static status_t +scsi_bus_raw_read(void *cookie, off_t position, void *data, + size_t *numBytes) +{ + *numBytes = 0; + return B_ERROR; +} + + +static status_t +scsi_bus_raw_write(void *cookie, off_t position, + const void *data, size_t *numBytes) +{ + *numBytes = 0; + return B_ERROR; +} + + +struct device_module_info gSCSIBusRawModule = { + { + SCSI_BUS_RAW_MODULE_NAME, + 0, + NULL + }, + + scsi_bus_raw_init, + scsi_bus_raw_uninit, + NULL, // removed + + scsi_bus_raw_open, + scsi_bus_raw_close, + scsi_bus_raw_free, + scsi_bus_raw_read, + scsi_bus_raw_write, + NULL, // io + scsi_bus_raw_control, + NULL, // select + NULL // deselect +}; Copied: haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/busses.cpp (from rev 40148, haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/busses.c) =================================================================== --- haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/busses.cpp (rev 0) +++ haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/busses.cpp 2011-01-08 19:29:20 UTC (rev 40163) @@ -0,0 +1,347 @@ +/* + * Copyright 2002/03, Thomas Kurschel. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +/* + Part of Open SCSI bus manager + + Bus node layer. + + Whenever a controller driver publishes a new controller, a new SCSI bus + for public and internal use is registered in turn. After that, this + bus is told to rescan for devices. For each device, there is a + device registered for peripheral drivers. (see devices.c) +*/ + +#include "scsi_internal.h" + +#include <string.h> +#include <malloc.h> + + +// bus service should hurry up a bit - good controllers don't take much time +// but are very happy to be busy; don't make it realtime though as we +// don't really need that but would risk to steel processing power of +// realtime-demanding threads +#define BUS_SERVICE_PRIORITY B_URGENT_DISPLAY_PRIORITY + + +/** implementation of service thread: + * it handles DPC and pending requests + */ + +static void +scsi_do_service(scsi_bus_info *bus) +{ + while (true) { + SHOW_FLOW0( 3, "" ); + + // handle DPCs first as they are more urgent + if (scsi_check_exec_dpc(bus)) + continue; + + if (scsi_check_exec_service(bus)) + continue; + + break; + } +} + + +/** main loop of service thread */ + +static int32 +scsi_service_threadproc(void *arg) +{ + scsi_bus_info *bus = (scsi_bus_info *)arg; + int32 processed_notifications = 0; + + SHOW_FLOW(3, "bus = %p", bus); + + while (true) { + // we handle multiple requests in scsi_do_service at once; + // to save time, we will acquire all notifications that are sent + // up to now at once. + // (Sadly, there is no "set semaphore to zero" function, so this + // is a poor-man emulation) + acquire_sem_etc(bus->start_service, processed_notifications + 1, 0, 0); + + SHOW_FLOW0( 3, "1" ); + + if (bus->shutting_down) + break; + + // get number of notifications _before_ servicing to make sure no new + // notifications are sent after do_service() + get_sem_count(bus->start_service, &processed_notifications); + + scsi_do_service(bus); + } + + return 0; +} + + +static scsi_bus_info * +scsi_create_bus(device_node *node, uint8 path_id) +{ + scsi_bus_info *bus; + int res; + + SHOW_FLOW0(3, ""); + + bus = (scsi_bus_info *)malloc(sizeof(*bus)); + if (bus == NULL) + return NULL; + + memset(bus, 0, sizeof(*bus)); + + bus->path_id = path_id; + + if (pnp->get_attr_uint32(node, SCSI_DEVICE_MAX_TARGET_COUNT, &bus->max_target_count, true) != B_OK) + bus->max_target_count = MAX_TARGET_ID + 1; + + bus->node = node; + bus->lock_count = bus->blocked[0] = bus->blocked[1] = 0; + bus->sim_overflow = 0; + bus->shutting_down = false; + + bus->waiting_devices = NULL; + //bus->resubmitted_req = NULL; + + bus->dpc_list = NULL; + + if ((bus->scan_lun_lock = create_sem(1, "scsi_scan_lun_lock")) < 0) { + res = bus->scan_lun_lock; + goto err6; + } + + bus->start_service = create_sem(0, "scsi_start_service"); + if (bus->start_service < 0) { + res = bus->start_service; + goto err4; + } + + res = INIT_BEN(&bus->mutex, "scsi_bus_mutex"); + if (res < B_OK) + goto err3; + + spinlock_irq_init(&bus->dpc_lock); + + res = scsi_init_ccb_alloc(bus); + if (res < B_OK) + goto err2; + + bus->service_thread = spawn_kernel_thread(scsi_service_threadproc, + "scsi_bus_service", BUS_SERVICE_PRIORITY, bus); + + if (bus->service_thread < 0) { + res = bus->service_thread; + goto err1; + } + + resume_thread(bus->service_thread); + + return bus; + +err1: + scsi_uninit_ccb_alloc(bus); +err2: + DELETE_BEN(&bus->mutex); +err3: + delete_sem(bus->start_service); +err4: + delete_sem(bus->scan_lun_lock); +err6: + free(bus); + return NULL; +} + + +static status_t +scsi_destroy_bus(scsi_bus_info *bus) +{ + int32 retcode; + + // noone is using this bus now, time to clean it up + bus->shutting_down = true; + release_sem(bus->start_service); + + wait_for_thread(bus->service_thread, &retcode); + + delete_sem(bus->start_service); + DELETE_BEN(&bus->mutex); + delete_sem(bus->scan_lun_lock); + + scsi_uninit_ccb_alloc(bus); + + return B_OK; +} + + +static status_t +scsi_init_bus(device_node *node, void **cookie) +{ + uint8 path_id; + scsi_bus_info *bus; + status_t res; + + SHOW_FLOW0( 3, "" ); + + if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, false) != B_OK) + return B_ERROR; + + bus = scsi_create_bus(node, path_id); + if (bus == NULL) + return B_NO_MEMORY; + + // extract controller/protocoll restrictions from node + if (pnp->get_attr_uint32(node, B_DMA_ALIGNMENT, &bus->dma_params.alignment, + true) != B_OK) + bus->dma_params.alignment = 0; + 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; + if (pnp->get_attr_uint32(node, B_DMA_BOUNDARY, + &bus->dma_params.dma_boundary, true) != B_OK) + bus->dma_params.dma_boundary = ~0; + 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; + 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; + + // do some sanity check: + bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment; + + if (bus->dma_params.alignment > B_PAGE_SIZE) { + SHOW_ERROR(0, "Alignment (0x%x) must be less then B_PAGE_SIZE", + (int)bus->dma_params.alignment); + res = B_ERROR; + goto err; + } + + if (bus->dma_params.max_sg_block_size < 1) { + SHOW_ERROR(0, "Max s/g block size (0x%x) is too small", + (int)bus->dma_params.max_sg_block_size); + res = B_ERROR; + goto err; + } + + if (bus->dma_params.dma_boundary < B_PAGE_SIZE - 1) { + SHOW_ERROR(0, "DMA boundary (0x%x) must be at least B_PAGE_SIZE", + (int)bus->dma_params.dma_boundary); + res = B_ERROR; + goto err; + } + + if (bus->dma_params.max_blocks < 1 || bus->dma_params.max_sg_blocks < 1) { + SHOW_ERROR(0, "Max blocks (%d) and max s/g blocks (%d) must be at least 1", + (int)bus->dma_params.max_blocks, (int)bus->dma_params.max_sg_blocks); + res = B_ERROR; + goto err; + } + + { + device_node *parent = pnp->get_parent_node(node); + pnp->get_driver(parent, (driver_module_info **)&bus->interface, + (void **)&bus->sim_cookie); + pnp->put_node(parent); + + bus->interface->set_scsi_bus(bus->sim_cookie, bus); + } + + // cache inquiry data + scsi_inquiry_path(bus, &bus->inquiry_data); + + // get max. number of commands on bus + bus->left_slots = bus->inquiry_data.hba_queue_size; + SHOW_FLOW( 3, "Bus has %d slots", bus->left_slots ); + + *cookie = bus; + + return B_OK; + +err: + scsi_destroy_bus(bus); + return res; +} + + +static void +scsi_uninit_bus(scsi_bus_info *bus) +{ + scsi_destroy_bus(bus); +} + + +uchar +scsi_inquiry_path(scsi_bus bus, scsi_path_inquiry *inquiry_data) +{ + SHOW_FLOW(4, "path_id=%d", bus->path_id); + return bus->interface->path_inquiry(bus->sim_cookie, inquiry_data); +} + + +static uchar +scsi_reset_bus(scsi_bus_info *bus) +{ + return bus->interface->reset_bus(bus->sim_cookie); +} + + +static status_t +scsi_bus_module_init(void) +{ + SHOW_FLOW0(4, ""); + return init_temp_sg(); +} + + +static status_t +scsi_bus_module_uninit(void) +{ + SHOW_INFO0(4, ""); + + uninit_temp_sg(); + return B_OK; +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + return scsi_bus_module_init(); + case B_MODULE_UNINIT: + return scsi_bus_module_uninit(); + + default: + return B_ERROR; + } +} + + +scsi_bus_interface scsi_bus_module = { + { + { + SCSI_BUS_MODULE_NAME, + 0, + std_ops + }, + + NULL, // supported devices + NULL, // register node + scsi_init_bus, + (void (*)(void *))scsi_uninit_bus, + (status_t (*)(void *))scsi_scan_bus, + (status_t (*)(void *))scsi_scan_bus, + NULL + }, + + scsi_inquiry_path, + scsi_reset_bus, +}; Copied: haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/ccb.cpp (from rev 40148, haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/ccb.c) =================================================================== --- haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/ccb.cpp (rev 0) +++ haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/ccb.cpp 2011-01-08 19:29:20 UTC (rev 40163) @@ -0,0 +1,115 @@ +/* +** Copyright 2002/03, Thomas Kurschel. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + +/* + Part of Open SCSI bus manager + + CCB manager + + As allocation of ccb can be on the paging path we must use a + locked pool. +*/ + +#include "scsi_internal.h" + + + +// ccb are relatively large, so don't make it too small to not waste memory +#define CCB_CHUNK_SIZE 16*1024 + +// maximum number of CCBs - probably, we want to make that editable +// it must be at least 1 for normal use and 1 for stand-by autosense request +#define CCB_NUM_MAX 128 + + +scsi_ccb * +scsi_alloc_ccb(scsi_device_info *device) +{ + scsi_ccb *ccb; + + SHOW_FLOW0( 3, "" ); + + ccb = (scsi_ccb *)locked_pool->alloc(device->bus->ccb_pool); + ccb->state = SCSI_STATE_FINISHED; + ccb->device = device; + ccb->target_id = device->target_id; + ccb->target_lun = device->target_lun; + + // reset some very important fields + // TODO: should we better omit that to find bugs easier? + ccb->sg_list = NULL; + ccb->io_operation = NULL; + ccb->sort = -1; + + SHOW_FLOW(3, "path=%d", ccb->path_id); + + return ccb; +} + + +void +scsi_free_ccb(scsi_ccb *ccb) +{ + SHOW_FLOW0( 3, "" ); + + if (ccb->state != SCSI_STATE_FINISHED) + panic("Tried to free ccb that's still in use (state %d)\n", ccb->state); + + ccb->state = SCSI_STATE_FREE; + + locked_pool->free(ccb->bus->ccb_pool, ccb); +} + + +static status_t +ccb_low_alloc_hook(void *block, void *arg) +{ + scsi_ccb *ccb = (scsi_ccb *)block; + scsi_bus_info *bus = (scsi_bus_info *)arg; + status_t res; + + ccb->bus = bus; + ccb->path_id = bus->path_id; + ccb->state = SCSI_STATE_FREE; + + if ((res = ccb->completion_sem = create_sem(0, "ccb_sem")) < 0) + return res; + + return B_OK; +} + + +static void +ccb_low_free_hook(void *block, void *arg) +{ + scsi_ccb *ccb = (scsi_ccb *)block; + + delete_sem(ccb->completion_sem); +} + + +status_t +scsi_init_ccb_alloc(scsi_bus_info *bus) +{ + // initially, we want no CCB allocated as the path_id of + // the bus is not ready yet so the CCB cannot be initialized + // correctly + bus->ccb_pool = locked_pool->create(sizeof(scsi_ccb), sizeof(uint32) - 1, 0, + CCB_CHUNK_SIZE, CCB_NUM_MAX, 0, "scsi_ccb_pool", B_CONTIGUOUS, + ccb_low_alloc_hook, ccb_low_free_hook, bus); + + if (bus->ccb_pool == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + +void +scsi_uninit_ccb_alloc(scsi_bus_info *bus) +{ + locked_pool->destroy(bus->ccb_pool); +} + Copied: haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/device_scan.cpp (from rev 40148, haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/device_scan.c) =================================================================== --- haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/device_scan.cpp (rev 0) +++ haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/device_scan.cpp 2011-01-08 19:29:20 UTC (rev 40163) @@ -0,0 +1,287 @@ +/* + * Copyright 2004-2007, Haiku, Inc. All RightsReserved. + * Copyright 2002/03, Thomas Kurschel. All rights reserved. + * + * Distributed under the terms of the MIT License. + */ + +/*! + Device scanner. + + Scans SCSI busses for devices. Scanning is initiated by + a SCSI device node probe (see device_mgr.c) +*/ + + +#include "scsi_internal.h" + +#include <string.h> +#include <stdlib.h> + +#include <algorithm> + + +/*! send TUR + result: true, if device answered + false, if there is no device +*/ +static bool +scsi_scan_send_tur(scsi_ccb *worker_req) +{ + scsi_cmd_tur *cmd = (scsi_cmd_tur *)worker_req->cdb; + + SHOW_FLOW0( 3, "" ); + + memset( cmd, 0, sizeof( *cmd )); + cmd->opcode = SCSI_OP_TEST_UNIT_READY; + + worker_req->sg_list = NULL; + worker_req->data = NULL; + worker_req->data_length = 0; + worker_req->cdb_length = sizeof(*cmd); + worker_req->timeout = 0; + worker_req->sort = -1; + worker_req->flags = SCSI_DIR_NONE; + + scsi_sync_io( worker_req ); + + SHOW_FLOW( 3, "status=%x", worker_req->subsys_status ); + + // as this command was only for syncing, we ignore almost all errors + switch (worker_req->subsys_status) { + case SCSI_SEL_TIMEOUT: + // there seems to be no device around + return false; + + default: + return true; + } +} + + +/*! get inquiry data + returns true on success +*/ +static bool +scsi_scan_get_inquiry(scsi_ccb *worker_req, scsi_res_inquiry *new_inquiry_data) +{ + scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)worker_req->cdb; + scsi_device_info *device = worker_req->device; + + SHOW_FLOW0(3, ""); + + // in case not whole structure gets transferred, we set remaining data to zero + memset(new_inquiry_data, 0, sizeof(*new_inquiry_data)); + + cmd->opcode = SCSI_OP_INQUIRY; + cmd->lun = device->target_lun; + cmd->evpd = 0; + cmd->page_code = 0; + cmd->allocation_length = sizeof(*new_inquiry_data); + + worker_req->sg_list = NULL; + worker_req->data = (uchar *)new_inquiry_data; + worker_req->data_length = sizeof(*new_inquiry_data); + worker_req->cdb_length = 6; + worker_req->timeout = SCSI_STD_TIMEOUT; + worker_req->sort = -1; + worker_req->flags = SCSI_DIR_IN; + + scsi_sync_io(worker_req); + + switch (worker_req->subsys_status) { + case SCSI_REQ_CMP: { + char vendor[9], product[17], rev[5]; + + SHOW_FLOW0(3, "send successfully"); + + // we could check transmission length here, but as we reset + // missing bytes before, we get kind of valid data anyway (hopefully) + + strlcpy(vendor, new_inquiry_data->vendor_ident, sizeof(vendor)); + strlcpy(product, new_inquiry_data->product_ident, sizeof(product)); + strlcpy(rev, new_inquiry_data->product_rev, sizeof(rev)); + + SHOW_INFO(3, "device type: %d, qualifier: %d, removable: %d, ANSI version: %d, response data format: %d\n" + "vendor: %s, product: %s, rev: %s", + new_inquiry_data->device_type, new_inquiry_data->device_qualifier, + new_inquiry_data->removable_medium, new_inquiry_data->ansi_version, + new_inquiry_data->response_data_format, + vendor, product, rev); + + SHOW_INFO(3, "additional_length: %d", new_inquiry_data->additional_length + 4); + + // time to show standards the device conforms to; + // unfortunately, ATAPI CD-ROM drives tend to tell that they have + // only minimal info (36 bytes), but still they return (valid!) 96 bytes - + // bad luck + if (std::min((int)cmd->allocation_length, + new_inquiry_data->additional_length + 4) + >= (int)offsetof(scsi_res_inquiry, version_descriptor[9])) { + int i, previousStandard = -1; + + for (i = 0; i < 8; ++i) { + int standard = B_BENDIAN_TO_HOST_INT16( + new_inquiry_data->version_descriptor[i]); + + // omit standards reported twice + if (standard != previousStandard && standard != 0) + SHOW_INFO(3, "standard: %04x", standard); + + previousStandard = standard; + } + } + + //snooze( 1000000 ); + + /* { + unsigned int i; + + for( i = 0; i < worker_req->data_length - worker_req->data_resid; ++i ) { + dprintf( "%2x ", *((char *)new_inquiry_data + i) ); + } + + dprintf( "\n" ); + }*/ + + return true; + } + + default: + return false; + } +} + + +status_t +scsi_scan_lun(scsi_bus_info *bus, uchar target_id, uchar target_lun) +{ + scsi_ccb *worker_req; + scsi_res_inquiry new_inquiry_data; + status_t res; + scsi_device_info *device; + bool found; + + //snooze(1000000); + + SHOW_FLOW(3, "%d:%d:%d", bus->path_id, target_id, target_lun); + + res = scsi_force_get_device(bus, target_id, target_lun, &device); + if (res != B_OK) + goto err; + + //SHOW_FLOW(3, "temp_device: %d", (int)temp_device); + + worker_req = scsi_alloc_ccb(device); + if (worker_req == NULL) { + // there is no out-of-mem code + res = B_NO_MEMORY; + goto err2; + } + + SHOW_FLOW0(3, "2"); + + worker_req->flags = SCSI_DIR_IN; + + // to give controller a chance to transfer speed negotiation, we + // send a TUR first; unfortunatily, some devices don't like TURing + // invalid luns apart from lun 0... + if (device->target_lun == 0) { + if (!scsi_scan_send_tur(worker_req)) { + // TBD: need better error code like "device not found" + res = B_NAME_NOT_FOUND; + goto err3; + } + } + + // get inquiry data to be used as identification + // and to check whether there is a device at all + found = scsi_scan_get_inquiry(worker_req, &new_inquiry_data) + && new_inquiry_data.device_qualifier == scsi_periph_qual_connected; + + // get rid of temporary device - as soon as the device is + // registered, it can be loaded, and we don't want two data + // structures for one device (the temporary and the official one) + scsi_free_ccb(worker_req); + scsi_put_forced_device(device); + + if (!found) { + // TBD: better error code, s.a. + return B_NAME_NOT_FOUND; + } + + // !danger! + // if a new device is detected on the same connection, all connections + // to the old device are disabled; + // scenario: you plug in a device, scan the bus, replace the device and then + // open it; in this case, the connection seems to be to the old device, but really + // is to the new one; if you scan the bus now, the opened connection is disabled + // - bad luck - + // solution 1: scan device during each scsi_init_device + // disadvantage: it takes time and we had to submit commands during the load + // sequence, which could lead to deadlocks + // solution 2: device drivers must scan devices before first use + // disadvantage: it takes time and driver must perform a task that + // the bus_manager should really take care of + scsi_register_device(bus, target_id, target_lun, &new_inquiry_data); + + return B_OK; + +err3: + scsi_free_ccb(worker_req); +err2: + scsi_put_forced_device(device); +err: + return res; +} + + +status_t +scsi_scan_bus(scsi_bus_info *bus) +{ + int initiator_id, target_id; + scsi_path_inquiry inquiry; + uchar res; + + SHOW_FLOW0( 3, "" ); + + // get ID of initiator (i.e. controller) + res = scsi_inquiry_path(bus, &inquiry); + if (res != SCSI_REQ_CMP) + return B_ERROR; + + initiator_id = inquiry.initiator_id; + + SHOW_FLOW(3, "initiator_id=%d", initiator_id); + + // tell SIM to rescan bus (needed at least by IDE translator) + // as this function is optional for SIM, we ignore its result + bus->interface->scan_bus(bus->sim_cookie); + + for (target_id = 0; target_id < (int)bus->max_target_count; ++target_id) { + int lun; + + SHOW_FLOW(3, "target: %d", target_id); + + if (target_id == initiator_id) + continue; + + // TODO: there are a lot of devices out there that go mad if you probe + // anything but LUN 0, so we should probably add a black-list + // or something + for (lun = 0; lun <= MAX_LUN_ID; ++lun) { + status_t res; + + SHOW_FLOW(3, "lun: %d", lun); + + res = scsi_scan_lun(bus, target_id, lun); + + // if there is no device at lun 0, there's probably no device at all + if (lun == 0 && res != SCSI_REQ_CMP) + break; + } + } + + SHOW_FLOW0(3, "done"); + return B_OK; +} Copied: haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/devices.cpp (from rev 40148, haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/devices.c) =================================================================== --- haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/devices.cpp (rev 0) +++ haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi/devices.cpp 2011-01-08 19:29:20 UTC (rev 40163) @@ -0,0 +1,525 @@ +/* + * Copyright 2004-2006, Haiku, Inc. All RightsReserved. + * Copyright 2002/03, Thomas Kurschel. All rights reserved. + * + * Distributed under the terms of the MIT License. + */ + +/* + Device node layer. + + When a SCSI bus is registered, this layer scans for SCSI devices + and registers a node for each of them. Peripheral drivers are on + top of these nodes. +*/ + +#include "scsi_internal.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include <algorithm> + + +/** free autosense request of device */ + +static void +scsi_free_autosense_request(scsi_device_info *device) +{ + SHOW_FLOW0( 3, "" ); + + if (device->auto_sense_request != NULL) { + scsi_free_ccb(device->auto_sense_request); + device->auto_sense_request = NULL; + } + + if (device->auto_sense_area > 0) { + delete_area(device->auto_sense_area); + device->auto_sense_area = 0; + } +} + + +/** free all data of device */ + +static void +scsi_free_device(scsi_device_info *device) +{ [... truncated: 2135 lines follow ...]