[haiku-commits] r40163 - haiku/branches/developer/bonefish/signals/src/add-ons/kernel/bus_managers/scsi

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 8 Jan 2011 20:29:21 +0100 (CET)

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 ...]

Other related posts: