* Made block_io.h usable from C++ (which doesn't like "typedef a *a" anymore).
* Renamed scsi_dsk to scsi_disk. * Joined all scsi_disk sources together to a single scsi_disk.cpp file. * Cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25737 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
654aaf6ee2
commit
fc128a4c76
@ -172,7 +172,7 @@ AddDriversToHaikuImage : console dprintf $(X86_ONLY)keyboard null
|
||||
AddDriversToHaikuImage audio hmulti : $(BEOS_ADD_ONS_DRIVERS_AUDIO) ;
|
||||
AddDriversToHaikuImage midi : $(BEOS_ADD_ONS_DRIVERS_MIDI) ;
|
||||
AddDriversToHaikuImage bus : usb_raw ; # fw_raw
|
||||
AddDriversToHaikuImage disk scsi : scsi_dsk ; #scsi_cd;
|
||||
AddDriversToHaikuImage disk scsi : scsi_disk ; #scsi_cd;
|
||||
AddDriversToHaikuImage disk usb : usb_disk ;
|
||||
AddDriversToHaikuImage disk virtual : nbd ;
|
||||
AddDriversToHaikuImage dvb : cx23882 ;
|
||||
@ -360,7 +360,7 @@ AddBootModuleSymlinksToHaikuImage
|
||||
$(PPC_ONLY)openpic
|
||||
block_io ide_adapter locked_pool scsi_periph
|
||||
generic_ide_pci ahci silicon_image_3112 # $(X86_ONLY)ide_isa legacy_sata
|
||||
scsi_dsk #scsi_cd
|
||||
scsi_disk #scsi_cd
|
||||
intel
|
||||
bfs
|
||||
;
|
||||
|
@ -22,7 +22,7 @@ typedef struct block_io_device_info *block_io_device;
|
||||
typedef struct block_io_handle_info *block_io_handle;
|
||||
|
||||
// cookies issued by device driver
|
||||
typedef struct block_device_handle_cookie *block_device_handle_cookie;
|
||||
typedef struct block_device_handle_cookie block_device_handle_cookie;
|
||||
|
||||
|
||||
// two reason why to use array of size 1:
|
||||
@ -69,16 +69,16 @@ typedef struct block_device_interface {
|
||||
// iovecs are physical address here
|
||||
// pos and num_blocks are in blocks; bytes_transferred in bytes
|
||||
// vecs are guaranteed to describe enough data for given block count
|
||||
status_t (*open)(block_device_cookie *cookie, block_device_handle_cookie *handle);
|
||||
status_t (*close)(block_device_handle_cookie handle);
|
||||
status_t (*free)(block_device_handle_cookie handle);
|
||||
status_t (*open)(block_device_cookie *cookie, block_device_handle_cookie **handle);
|
||||
status_t (*close)(block_device_handle_cookie *handle);
|
||||
status_t (*free)(block_device_handle_cookie *handle);
|
||||
|
||||
status_t (*read)(block_device_handle_cookie handle, const phys_vecs *vecs, off_t pos,
|
||||
status_t (*read)(block_device_handle_cookie *handle, const phys_vecs *vecs, off_t pos,
|
||||
size_t num_blocks, uint32 block_size, size_t *bytes_transferred);
|
||||
status_t (*write)(block_device_handle_cookie handle, const phys_vecs *vecs, off_t pos,
|
||||
status_t (*write)(block_device_handle_cookie *handle, const phys_vecs *vecs, off_t pos,
|
||||
size_t num_blocks, uint32 block_size, size_t *bytes_transferred);
|
||||
|
||||
status_t (*ioctl)(block_device_handle_cookie handle, int op, void *buf, size_t len);
|
||||
status_t (*ioctl)(block_device_handle_cookie *handle, int op, void *buf, size_t len);
|
||||
} block_device_interface;
|
||||
|
||||
#define B_BLOCK_IO_DEVICE_MODULE_NAME "generic/block_io/device_v1"
|
||||
|
@ -1,4 +1,4 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers disk scsi ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk scsi scsi_cd ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk scsi scsi_dsk ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk scsi scsi_disk ;
|
||||
|
7
src/add-ons/kernel/drivers/disk/scsi/scsi_disk/Jamfile
Normal file
7
src/add-ons/kernel/drivers/disk/scsi/scsi_disk/Jamfile
Normal file
@ -0,0 +1,7 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers disk scsi scsi_disk ;
|
||||
|
||||
UsePrivateHeaders drivers kernel ;
|
||||
|
||||
KernelAddon scsi_disk :
|
||||
scsi_disk.cpp
|
||||
;
|
495
src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp
Normal file
495
src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp
Normal file
@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*! Peripheral driver to handle any kind of SCSI disks,
|
||||
i.e. hard disk and floopy disks (ZIP etc.)
|
||||
|
||||
Much work is done by scsi_periph and block_io.
|
||||
|
||||
You'll find das_... all over the place. This stands for
|
||||
"Direct Access Storage" which is the official SCSI name for
|
||||
normal (floppy/hard/ZIP)-disk drives.
|
||||
*/
|
||||
|
||||
|
||||
#include "scsi_disk.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
//#define TRACE_SCSI_DISK
|
||||
#ifdef TRACE_SCSI_DISK
|
||||
# define TRACE(x...) dprintf("scsi_disk: " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
static scsi_periph_interface *sSCSIPeripheral;
|
||||
static device_manager_info *sDeviceManager;
|
||||
static block_io_for_driver_interface *sBlockIO;
|
||||
|
||||
|
||||
static status_t
|
||||
update_capacity(das_device_info *device)
|
||||
{
|
||||
TRACE("update_capacity()\n");
|
||||
|
||||
scsi_ccb *ccb = device->scsi->alloc_ccb(device->scsi_device);
|
||||
if (ccb == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t status = sSCSIPeripheral->check_capacity(
|
||||
device->scsi_periph_device, ccb);
|
||||
|
||||
device->scsi->free_ccb(ccb);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_geometry(das_handle_info *handle, device_geometry *geometry)
|
||||
{
|
||||
das_device_info *device = handle->device;
|
||||
|
||||
status_t status = update_capacity(device);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
geometry->bytes_per_sector = device->block_size;
|
||||
geometry->sectors_per_track = 1;
|
||||
geometry->cylinder_count = device->capacity;
|
||||
geometry->head_count = 1;
|
||||
geometry->device_type = B_DISK;
|
||||
geometry->removable = device->removable;
|
||||
|
||||
// TBD: for all but CD-ROMs, read mode sense - medium type
|
||||
// (bit 7 of block device specific parameter for Optical Memory Block Device)
|
||||
// (same for Direct-Access Block Devices)
|
||||
// (same for write-once block devices)
|
||||
// (same for optical memory block devices)
|
||||
geometry->read_only = false;
|
||||
geometry->write_once = false;
|
||||
|
||||
TRACE("scsi_disk: get_geometry(): %ld, %ld, %ld, %ld, %d, %d, %d, %d\n",
|
||||
geometry->bytes_per_sector, geometry->sectors_per_track,
|
||||
geometry->cylinder_count, geometry->head_count, geometry->device_type,
|
||||
geometry->removable, geometry->read_only, geometry->write_once);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
load_eject(das_device_info *device, bool load)
|
||||
{
|
||||
TRACE("load_eject()\n");
|
||||
|
||||
scsi_ccb *ccb = device->scsi->alloc_ccb(device->scsi_device);
|
||||
if (ccb == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
err_res result = sSCSIPeripheral->send_start_stop(
|
||||
device->scsi_periph_device, ccb, load, true);
|
||||
|
||||
device->scsi->free_ccb(ccb);
|
||||
|
||||
return result.error_code;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
synchronize_cache(das_device_info *device)
|
||||
{
|
||||
TRACE("synchronize_cache()\n");
|
||||
|
||||
scsi_ccb *ccb = device->scsi->alloc_ccb(device->scsi_device);
|
||||
if (ccb == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
err_res result = sSCSIPeripheral->synchronize_cache(
|
||||
device->scsi_periph_device, ccb);
|
||||
|
||||
device->scsi->free_ccb(ccb);
|
||||
|
||||
return result.error_code;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
log2(uint32 x)
|
||||
{
|
||||
int y;
|
||||
|
||||
for (y = 31; y >= 0; --y) {
|
||||
if (x == ((uint32)1 << y))
|
||||
break;
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - block_io API
|
||||
|
||||
|
||||
static void
|
||||
das_set_device(das_device_info *info, block_io_device device)
|
||||
{
|
||||
info->block_io_device = device;
|
||||
|
||||
// and get (initial) capacity
|
||||
scsi_ccb *request = info->scsi->alloc_ccb(info->scsi_device);
|
||||
if (request == NULL)
|
||||
return;
|
||||
|
||||
sSCSIPeripheral->check_capacity(info->scsi_periph_device, request);
|
||||
info->scsi->free_ccb(request);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_open(das_device_info *device, das_handle_info **_cookie)
|
||||
{
|
||||
TRACE("open()\n");
|
||||
|
||||
das_handle_info *handle = (das_handle_info *)malloc(sizeof(*handle));
|
||||
if (handle == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
handle->device = device;
|
||||
|
||||
status_t status = sSCSIPeripheral->handle_open(device->scsi_periph_device,
|
||||
(periph_handle_cookie)handle, &handle->scsi_periph_handle);
|
||||
if (status < B_OK) {
|
||||
free(handle);
|
||||
return status;
|
||||
}
|
||||
|
||||
*_cookie = handle;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_close(das_handle_info *handle)
|
||||
{
|
||||
TRACE("close()\n");
|
||||
|
||||
sSCSIPeripheral->handle_close(handle->scsi_periph_handle);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_free(das_handle_info *handle)
|
||||
{
|
||||
TRACE("free()\n");
|
||||
|
||||
sSCSIPeripheral->handle_free(handle->scsi_periph_handle);
|
||||
free(handle);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_read(das_handle_info *handle, const phys_vecs *vecs, off_t pos,
|
||||
size_t num_blocks, uint32 block_size, size_t *bytes_transferred)
|
||||
{
|
||||
return sSCSIPeripheral->read(handle->scsi_periph_handle, vecs, pos,
|
||||
num_blocks, block_size, bytes_transferred, 10);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_write(das_handle_info *handle, const phys_vecs *vecs, off_t pos,
|
||||
size_t num_blocks, uint32 block_size, size_t *bytes_transferred)
|
||||
{
|
||||
return sSCSIPeripheral->write(handle->scsi_periph_handle, vecs, pos,
|
||||
num_blocks, block_size, bytes_transferred, 10);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_ioctl(das_handle_info *handle, int op, void *buffer, size_t length)
|
||||
{
|
||||
das_device_info *device = handle->device;
|
||||
|
||||
TRACE("ioctl(op = %d)\n", op);
|
||||
|
||||
switch (op) {
|
||||
case B_GET_DEVICE_SIZE:
|
||||
{
|
||||
status_t status = update_capacity(device);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
size_t size = device->capacity * device->block_size;
|
||||
return user_memcpy(buffer, &size, sizeof(size_t));
|
||||
}
|
||||
|
||||
case B_GET_GEOMETRY:
|
||||
{
|
||||
if (buffer == NULL /*|| length != sizeof(device_geometry)*/)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
device_geometry geometry;
|
||||
status_t status = get_geometry(handle, &geometry);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return user_memcpy(buffer, &geometry, sizeof(device_geometry));
|
||||
}
|
||||
|
||||
case B_GET_ICON:
|
||||
return sSCSIPeripheral->get_icon(device->removable
|
||||
? icon_type_floppy : icon_type_disk, (device_icon *)buffer);
|
||||
|
||||
case B_EJECT_DEVICE:
|
||||
case B_SCSI_EJECT:
|
||||
return load_eject(device, false);
|
||||
|
||||
case B_LOAD_MEDIA:
|
||||
return load_eject(device, true);
|
||||
|
||||
case B_FLUSH_DRIVE_CACHE:
|
||||
return synchronize_cache(device);
|
||||
|
||||
default:
|
||||
return sSCSIPeripheral->ioctl(handle->scsi_periph_handle, op,
|
||||
buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - scsi_periph callbacks
|
||||
|
||||
|
||||
static void
|
||||
das_set_capacity(das_device_info *device, uint64 capacity, uint32 blockSize)
|
||||
{
|
||||
TRACE("das_set_capacity(device = %p, capacity = %Ld, blockSize = %ld)\n",
|
||||
device, capacity, blockSize);
|
||||
|
||||
// get log2, if possible
|
||||
uint32 blockShift = log2(blockSize);
|
||||
|
||||
if ((1UL << blockShift) != blockSize)
|
||||
blockShift = 0;
|
||||
|
||||
device->capacity = capacity;
|
||||
device->block_size = blockSize;
|
||||
|
||||
sBlockIO->set_media_params(device->block_io_device, blockSize,
|
||||
blockShift, capacity);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
das_media_changed(das_device_info *device, scsi_ccb *request)
|
||||
{
|
||||
// do a capacity check
|
||||
// TBD: is this a good idea (e.g. if this is an empty CD)?
|
||||
sSCSIPeripheral->check_capacity(device->scsi_periph_device, request);
|
||||
}
|
||||
|
||||
|
||||
scsi_periph_callbacks callbacks = {
|
||||
(void (*)(periph_device_cookie, uint64, uint32))das_set_capacity,
|
||||
(void (*)(periph_device_cookie, scsi_ccb *))das_media_changed
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - driver module API
|
||||
|
||||
|
||||
static float
|
||||
das_supports_device(device_node *parent)
|
||||
{
|
||||
const char *bus;
|
||||
uint8 deviceType;
|
||||
|
||||
// make sure parent is really the SCSI bus manager
|
||||
if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
|
||||
return -1;
|
||||
|
||||
if (strcmp(bus, "scsi"))
|
||||
return 0.0;
|
||||
|
||||
// check whether it's really a Direct Access Device
|
||||
if (sDeviceManager->get_attr_uint8(parent, SCSI_DEVICE_TYPE_ITEM,
|
||||
&deviceType, true) != B_OK || deviceType != scsi_dev_direct_access)
|
||||
return 0.0;
|
||||
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
|
||||
/*! Called whenever a new device was added to system;
|
||||
if we really support it, we create a new node that gets
|
||||
server by the block_io module
|
||||
*/
|
||||
static status_t
|
||||
das_register_device(device_node *node)
|
||||
{
|
||||
const scsi_res_inquiry *deviceInquiry = NULL;
|
||||
uint8 deviceType;
|
||||
size_t inquiryLength;
|
||||
uint32 maxBlocks;
|
||||
|
||||
// check whether it's really a Direct Access Device
|
||||
if (sDeviceManager->get_attr_uint8(node, SCSI_DEVICE_TYPE_ITEM,
|
||||
&deviceType, true) != B_OK
|
||||
|| deviceType != scsi_dev_direct_access)
|
||||
return B_ERROR;
|
||||
|
||||
// get inquiry data
|
||||
if (sDeviceManager->get_attr_raw(node, SCSI_DEVICE_INQUIRY_ITEM,
|
||||
(const void **)&deviceInquiry, &inquiryLength, true) != B_OK
|
||||
|| inquiryLength < sizeof(deviceInquiry))
|
||||
return B_ERROR;
|
||||
|
||||
// get block limit of underlying hardware to lower it (if necessary)
|
||||
if (sDeviceManager->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM,
|
||||
&maxBlocks, true) != B_OK)
|
||||
maxBlocks = INT_MAX;
|
||||
|
||||
// using 10 byte commands, at most 0xffff blocks can be transmitted at once
|
||||
// (sadly, we cannot update this value later on if only 6 byte commands
|
||||
// are supported, but the block_io module can live with that)
|
||||
maxBlocks = min_c(maxBlocks, 0xffff);
|
||||
|
||||
// ready to register
|
||||
device_attr attrs[] = {
|
||||
// tell block_io whether the device is removable
|
||||
{"removable", B_UINT8_TYPE, {ui8: deviceInquiry->removable_medium}},
|
||||
// impose own max block restriction
|
||||
{B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, {ui32: maxBlocks}},
|
||||
// in general, any disk can be a BIOS drive (even ZIP-disks)
|
||||
{B_BLOCK_DEVICE_IS_BIOS_DRIVE, B_UINT8_TYPE, {ui8: 1}},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return sDeviceManager->register_node(node, SCSI_DISK_MODULE_NAME, attrs,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_init_driver(device_node *node, void **cookie)
|
||||
{
|
||||
das_device_info *device;
|
||||
status_t status;
|
||||
uint8 removable;
|
||||
|
||||
TRACE("das_init_driver");
|
||||
|
||||
status = sDeviceManager->get_attr_uint8(node, "removable",
|
||||
&removable, false);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
device = (das_device_info *)malloc(sizeof(*device));
|
||||
if (device == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset(device, 0, sizeof(*device));
|
||||
|
||||
device->node = node;
|
||||
device->removable = removable;
|
||||
|
||||
{
|
||||
device_node *parent = sDeviceManager->get_parent_node(node);
|
||||
sDeviceManager->get_driver(parent, (driver_module_info **)&device->scsi,
|
||||
(void **)&device->scsi_device);
|
||||
sDeviceManager->put_node(parent);
|
||||
}
|
||||
|
||||
status = sSCSIPeripheral->register_device((periph_device_cookie)device,
|
||||
&callbacks, device->scsi_device, device->scsi, device->node,
|
||||
device->removable, &device->scsi_periph_device);
|
||||
if (status != B_OK) {
|
||||
free(device);
|
||||
return status;
|
||||
}
|
||||
|
||||
*cookie = device;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
das_uninit_driver(void *_cookie)
|
||||
{
|
||||
das_device_info *device = (das_device_info *)_cookie;
|
||||
|
||||
sSCSIPeripheral->unregister_device(device->scsi_periph_device);
|
||||
free(device);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_register_child_devices(void *_cookie)
|
||||
{
|
||||
das_device_info *device = (das_device_info *)_cookie;
|
||||
status_t status;
|
||||
char *name;
|
||||
|
||||
name = sSCSIPeripheral->compose_device_name(device->node, "disk/scsi");
|
||||
if (name == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
status = sDeviceManager->publish_device(device->node, name,
|
||||
B_BLOCK_IO_DEVICE_MODULE_NAME);
|
||||
|
||||
free(name);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
module_dependency module_dependencies[] = {
|
||||
{SCSI_PERIPH_MODULE_NAME, (module_info **)&sSCSIPeripheral},
|
||||
{B_BLOCK_IO_FOR_DRIVER_MODULE_NAME, (module_info **)&sBlockIO},
|
||||
{B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager},
|
||||
{}
|
||||
};
|
||||
|
||||
block_device_interface sSCSIDiskModule = {
|
||||
{
|
||||
{
|
||||
SCSI_DISK_MODULE_NAME,
|
||||
0,
|
||||
NULL
|
||||
},
|
||||
|
||||
das_supports_device,
|
||||
das_register_device,
|
||||
das_init_driver,
|
||||
das_uninit_driver,
|
||||
das_register_child_devices,
|
||||
NULL, // rescan
|
||||
NULL, // removed
|
||||
},
|
||||
|
||||
(void (*)(block_device_cookie *, block_io_device)) &das_set_device,
|
||||
(status_t (*)(block_device_cookie *, block_device_handle_cookie **))&das_open,
|
||||
(status_t (*)(block_device_handle_cookie *)) &das_close,
|
||||
(status_t (*)(block_device_handle_cookie *)) &das_free,
|
||||
|
||||
(status_t (*)(block_device_handle_cookie *, const phys_vecs *,
|
||||
off_t, size_t, uint32, size_t *)) &das_read,
|
||||
(status_t (*)(block_device_handle_cookie *, const phys_vecs *,
|
||||
off_t, size_t, uint32, size_t *)) &das_write,
|
||||
|
||||
(status_t (*)(block_device_handle_cookie *, int, void *, size_t))&das_ioctl,
|
||||
};
|
||||
|
||||
module_info *modules[] = {
|
||||
(module_info *)&sSCSIDiskModule,
|
||||
NULL
|
||||
};
|
38
src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.h
Normal file
38
src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SCSI_DISK_H
|
||||
#define _SCSI_DISK_H
|
||||
|
||||
|
||||
#include <block_io.h>
|
||||
#include <device_manager.h>
|
||||
#include <scsi.h>
|
||||
#include <scsi_periph.h>
|
||||
|
||||
|
||||
#define SCSI_DISK_MODULE_NAME "drivers/disk/scsi/scsi_dsk/driver_v1"
|
||||
|
||||
|
||||
// must start as block_device_cookie
|
||||
typedef struct das_device_info {
|
||||
device_node *node;
|
||||
::scsi_periph_device scsi_periph_device;
|
||||
::scsi_device scsi_device;
|
||||
scsi_device_interface *scsi;
|
||||
::block_io_device block_io_device;
|
||||
|
||||
uint64 capacity;
|
||||
uint32 block_size;
|
||||
|
||||
bool removable; // true, if device is removable
|
||||
} das_device_info;
|
||||
|
||||
typedef struct das_handle_info {
|
||||
::scsi_periph_handle scsi_periph_handle;
|
||||
das_device_info *device;
|
||||
} das_handle_info;
|
||||
|
||||
#endif /* _SCSI_DISK_H */
|
@ -1,9 +0,0 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers disk scsi scsi_dsk ;
|
||||
|
||||
UsePrivateHeaders drivers kernel ;
|
||||
|
||||
KernelAddon scsi_dsk :
|
||||
device.c
|
||||
handle.c
|
||||
scsi_dsk.c
|
||||
;
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2007, Haiku, Inc. All RightsReserved.
|
||||
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
//! Device management.
|
||||
|
||||
|
||||
#include "scsi_dsk_int.h"
|
||||
|
||||
#include <pnp_devfs.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
status_t
|
||||
das_init_device(device_node *node, void **cookie)
|
||||
{
|
||||
das_device_info *device;
|
||||
status_t status;
|
||||
uint8 removable;
|
||||
|
||||
SHOW_FLOW0(3, "");
|
||||
|
||||
status = pnp->get_attr_uint8(node, "removable",
|
||||
&removable, false);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
device = (das_device_info *)malloc(sizeof(*device));
|
||||
if (device == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset(device, 0, sizeof(*device));
|
||||
|
||||
device->node = node;
|
||||
device->removable = removable;
|
||||
|
||||
{
|
||||
device_node *parent = pnp->get_parent_node(node);
|
||||
pnp->get_driver(parent, (driver_module_info **)&device->scsi,
|
||||
(void **)&device->scsi_device);
|
||||
pnp->put_node(parent);
|
||||
}
|
||||
|
||||
status = scsi_periph->register_device((periph_device_cookie)device,
|
||||
&callbacks, device->scsi_device, device->scsi, device->node,
|
||||
device->removable, &device->scsi_periph_device);
|
||||
if (status != B_OK) {
|
||||
free(device);
|
||||
return status;
|
||||
}
|
||||
|
||||
SHOW_FLOW0(3, "done");
|
||||
|
||||
*cookie = device;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
das_uninit_device(void *_cookie)
|
||||
{
|
||||
das_device_info *device = (das_device_info *)_cookie;
|
||||
|
||||
scsi_periph->unregister_device(device->scsi_periph_device);
|
||||
free(device);
|
||||
}
|
||||
|
||||
|
||||
/** called whenever a new device was added to system;
|
||||
* if we really support it, we create a new node that gets
|
||||
* server by the block_io module
|
||||
*/
|
||||
|
||||
status_t
|
||||
das_device_added(device_node *node)
|
||||
{
|
||||
const scsi_res_inquiry *deviceInquiry = NULL;
|
||||
uint8 device_type;
|
||||
size_t inquiryLength;
|
||||
uint32 max_blocks;
|
||||
|
||||
// check whether it's really a Direct Access Device
|
||||
if (pnp->get_attr_uint8(node, SCSI_DEVICE_TYPE_ITEM, &device_type, true) != B_OK
|
||||
|| device_type != scsi_dev_direct_access)
|
||||
return B_ERROR;
|
||||
|
||||
// get inquiry data
|
||||
if (pnp->get_attr_raw(node, SCSI_DEVICE_INQUIRY_ITEM,
|
||||
(const void **)&deviceInquiry, &inquiryLength, true) != B_OK
|
||||
|| inquiryLength < sizeof(deviceInquiry))
|
||||
return B_ERROR;
|
||||
|
||||
// get block limit of underlying hardware to lower it (if necessary)
|
||||
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &max_blocks,
|
||||
true) != B_OK)
|
||||
max_blocks = INT_MAX;
|
||||
|
||||
// using 10 byte commands, at most 0xffff blocks can be transmitted at once
|
||||
// (sadly, we cannot update this value later on if only 6 byte commands
|
||||
// are supported, but the block_io module can live with that)
|
||||
max_blocks = min(max_blocks, 0xffff);
|
||||
|
||||
// ready to register
|
||||
{
|
||||
device_attr attrs[] = {
|
||||
// tell block_io whether the device is removable
|
||||
{ "removable", B_UINT8_TYPE, { ui8: deviceInquiry->removable_medium }},
|
||||
// impose own max block restriction
|
||||
{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: max_blocks }},
|
||||
// in general, any disk can be a BIOS drive (even ZIP-disks)
|
||||
{ B_BLOCK_DEVICE_IS_BIOS_DRIVE, B_UINT8_TYPE, { ui8: 1 }},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return pnp->register_node(node, SCSI_DSK_MODULE_NAME, attrs, NULL,
|
||||
NULL);
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*! File handle management. */
|
||||
|
||||
#include "scsi_dsk_int.h"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
|
||||
status_t
|
||||
das_open(das_device_info *device, das_handle_info **handle_out)
|
||||
{
|
||||
das_handle_info *handle;
|
||||
int res;
|
||||
|
||||
SHOW_FLOW0(3, "");
|
||||
|
||||
handle = (das_handle_info *)malloc(sizeof(*handle));
|
||||
if (handle == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
handle->device = device;
|
||||
|
||||
res = scsi_periph->handle_open(device->scsi_periph_device,
|
||||
(periph_handle_cookie)handle,
|
||||
&handle->scsi_periph_handle);
|
||||
if (res < 0) {
|
||||
free(handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
SHOW_FLOW0(3, "opened");
|
||||
|
||||
*handle_out = handle;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
das_close(das_handle_info *handle)
|
||||
{
|
||||
SHOW_FLOW0(3, "");
|
||||
|
||||
scsi_periph->handle_close(handle->scsi_periph_handle);
|
||||
|
||||
SHOW_FLOW0(3, "done");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
das_free(das_handle_info *handle)
|
||||
{
|
||||
SHOW_FLOW0(3, "");
|
||||
|
||||
scsi_periph->handle_free(handle->scsi_periph_handle);
|
||||
free(handle);
|
||||
|
||||
SHOW_FLOW0(3, "done");
|
||||
|
||||
return B_OK;
|
||||
}
|
@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Part of Open SCSI Disk Driver
|
||||
|
||||
Everything doing the real input/output stuff.
|
||||
*/
|
||||
|
||||
|
||||
#include "scsi_dsk_int.h"
|
||||
|
||||
#define DAS_STD_TIMEOUT 10
|
||||
|
||||
|
||||
// we don't want to inline this function - it's just not worth it
|
||||
static int das_read_write(das_handle_info *handle, const phys_vecs *vecs,
|
||||
off_t pos, size_t num_blocks, uint32 block_size, size_t *bytes_transferred,
|
||||
bool write);
|
||||
|
||||
|
||||
status_t
|
||||
das_read(das_handle_info *handle, const phys_vecs *vecs, off_t pos, size_t numBlocks,
|
||||
uint32 blockSize, size_t *bytesTransferred)
|
||||
{
|
||||
return das_read_write(handle, vecs, pos, numBlocks, blockSize,
|
||||
bytesTransferred, false);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
das_write(das_handle_info *handle, const phys_vecs *vecs, off_t pos, size_t numBlocks,
|
||||
uint32 blockSize, size_t *bytesTransferred)
|
||||
{
|
||||
return das_read_write(handle, vecs, pos, numBlocks, blockSize,
|
||||
bytesTransferred, true);
|
||||
}
|
||||
|
||||
|
||||
/** universal read/write function */
|
||||
|
||||
static int
|
||||
das_read_write(das_handle_info *handle, const phys_vecs *vecs, off_t pos64,
|
||||
size_t num_blocks, uint32 block_size, size_t *bytes_transferred, bool write)
|
||||
{
|
||||
das_device_info *device = handle->device;
|
||||
scsi_ccb *request;
|
||||
err_res res;
|
||||
int retries = 0;
|
||||
int err;
|
||||
uint32 pos = pos64;
|
||||
|
||||
// don't test rw10_enabled restrictions - this flag may get changed
|
||||
request = device->scsi->alloc_ccb(device->scsi_device);
|
||||
if (request == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
do {
|
||||
size_t num_bytes;
|
||||
bool is_rw10;
|
||||
|
||||
request->flags = write ? SCSI_DIR_OUT : SCSI_DIR_IN;
|
||||
|
||||
// make sure we avoid 10 byte commands if they aren't supported
|
||||
if (!device->rw10_enabled) {
|
||||
// restricting transfer is OK - the block manager will
|
||||
// take care of transferring the rest
|
||||
if (num_blocks > 0x100)
|
||||
num_blocks = 0x100;
|
||||
|
||||
// no way to break the 21 bit address limit
|
||||
if (pos64 > 0x200000) {
|
||||
err = B_BAD_VALUE;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
// don't allow transfer cross the 24 bit address limit
|
||||
// (I'm not sure whether this is allowed, but this way we
|
||||
// are sure to not ask for trouble)
|
||||
num_blocks = min(num_blocks, 0x100000 - pos);
|
||||
}
|
||||
|
||||
num_bytes = num_blocks * block_size;
|
||||
|
||||
request->data = NULL;
|
||||
request->sg_list = vecs->vec;
|
||||
request->data_len = num_bytes;
|
||||
request->sglist_cnt = vecs->num;
|
||||
request->sort = pos;
|
||||
request->timeout = DAS_STD_TIMEOUT;
|
||||
// see whether daemon instructed us to post an ordered command;
|
||||
// reset flag after read
|
||||
request->flags = atomic_and(&device->next_tag_action, 0);
|
||||
|
||||
SHOW_FLOW(3, "ordered: %s",
|
||||
(request->flags & SCSI_ORDERED_QTAG) == 0 ? "yes" : "no");
|
||||
|
||||
// use 6 byte commands whenever possible
|
||||
if (pos + num_blocks < 0x200000 && num_blocks <= 0x100) {
|
||||
scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb;
|
||||
|
||||
is_rw10 = false;
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->opcode = write ? SCSI_OP_WRITE_6 : SCSI_OP_READ_6;
|
||||
cmd->high_LBA = (pos >> 16) & 0x1f;
|
||||
cmd->mid_LBA = (pos >> 8) & 0xff;
|
||||
cmd->low_LBA = pos & 0xff;
|
||||
cmd->length = num_blocks;
|
||||
|
||||
request->cdb_len = sizeof(*cmd);
|
||||
} else {
|
||||
scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb;
|
||||
|
||||
is_rw10 = true;
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->opcode = write ? SCSI_OP_WRITE_10 : SCSI_OP_READ_10;
|
||||
cmd->RelAdr = 0;
|
||||
cmd->FUA = 0;
|
||||
cmd->DPO = 0;
|
||||
|
||||
cmd->top_LBA = (pos >> 24) & 0xff;
|
||||
cmd->high_LBA = (pos >> 16) & 0xff;
|
||||
cmd->mid_LBA = (pos >> 8) & 0xff;
|
||||
cmd->low_LBA = pos & 0xff;
|
||||
|
||||
cmd->high_length = (num_blocks >> 8) & 0xff;
|
||||
cmd->low_length = num_blocks & 0xff;
|
||||
|
||||
request->cdb_len = sizeof(*cmd);
|
||||
}
|
||||
|
||||
// last chance to detect errors that occured during concurrent accesses
|
||||
err = handle->pending_error;
|
||||
if (err)
|
||||
goto abort;
|
||||
|
||||
device->scsi->scsi_io(request);
|
||||
|
||||
acquire_sem(request->completion_sem);
|
||||
|
||||
// ask generic peripheral layer what to do now
|
||||
res = scsi_periph->check_error(device->scsi_periph_device, request);
|
||||
|
||||
switch (res.action) {
|
||||
case err_act_ok:
|
||||
*bytes_transferred = num_bytes - request->data_resid;
|
||||
break;
|
||||
|
||||
case err_act_start:
|
||||
res = scsi_periph->send_start_stop(device->scsi_periph_device,
|
||||
request, 1, device->removable);
|
||||
if (res.action == err_act_ok)
|
||||
res.action = err_act_retry;
|
||||
break;
|
||||
|
||||
case err_act_invalid_req:
|
||||
// if this was a 10 byte command, the device probably doesn't
|
||||
// support them, so disable them and retry
|
||||
if (is_rw10) {
|
||||
atomic_and(&device->rw10_enabled, 0);
|
||||
res.action = err_act_retry;
|
||||
} else
|
||||
res.action = err_act_fail;
|
||||
break;
|
||||
}
|
||||
} while ((res.action == err_act_retry && retries++ < 3)
|
||||
|| (res.action == err_act_many_retries && retries++ < 30));
|
||||
|
||||
device->scsi->free_ccb(request);
|
||||
|
||||
// peripheral layer only created "read" error, so we have to
|
||||
// map them to "write" errors if this was a write request
|
||||
if (res.error_code == B_DEV_READ_ERROR && write)
|
||||
return B_DEV_WRITE_ERROR;
|
||||
|
||||
return res.error_code;
|
||||
|
||||
abort:
|
||||
device->scsi->free_ccb(request);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** kernel daemon
|
||||
* once in a minute, it sets a flag so that the next command is executed
|
||||
* ordered; this way, we avoid starvation of SCSI commands inside the
|
||||
* SCSI queuing system - the ordered command waits for all previous
|
||||
* commands and thus no command can starve longer then a minute
|
||||
*/
|
||||
|
||||
void
|
||||
das_sync_queue_daemon(void *arg, int iteration)
|
||||
{
|
||||
das_device_info *device = (das_device_info *)arg;
|
||||
|
||||
atomic_or(&device->next_tag_action, SCSI_ORDERED_QTAG);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
das_handle_set_error(das_handle_info *handle, status_t errorCode)
|
||||
{
|
||||
handle->pending_error = errorCode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
das_handle_get_error(das_handle_info *handle)
|
||||
{
|
||||
return handle->pending_error;
|
||||
}
|
@ -1,357 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*
|
||||
You'll find das_... all over the place. This stands for
|
||||
"Direct Access Storage" which is the official SCSI name for
|
||||
normal (floppy/hard/ZIP)-disk drives.
|
||||
*/
|
||||
|
||||
|
||||
#include "scsi_dsk_int.h"
|
||||
#include <scsi.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
extern block_device_interface das_interface;
|
||||
|
||||
scsi_periph_interface *scsi_periph;
|
||||
device_manager_info *pnp;
|
||||
block_io_for_driver_interface *gBlockIO;
|
||||
|
||||
|
||||
static void
|
||||
das_set_device(das_device_info *info, block_io_device device)
|
||||
{
|
||||
scsi_ccb *request;
|
||||
|
||||
info->block_io_device = device;
|
||||
|
||||
// and get (initial) capacity
|
||||
request = info->scsi->alloc_ccb(info->scsi_device);
|
||||
if (request == NULL)
|
||||
return;
|
||||
|
||||
scsi_periph->check_capacity(info->scsi_periph_device, request);
|
||||
info->scsi->free_ccb(request);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_read(das_handle_info *handle, const phys_vecs *vecs, off_t pos,
|
||||
size_t num_blocks, uint32 block_size, size_t *bytes_transferred)
|
||||
{
|
||||
return scsi_periph->read(handle->scsi_periph_handle, vecs, pos,
|
||||
num_blocks, block_size, bytes_transferred, 10);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_write(das_handle_info *handle, const phys_vecs *vecs, off_t pos,
|
||||
size_t num_blocks, uint32 block_size, size_t *bytes_transferred)
|
||||
{
|
||||
return scsi_periph->write(handle->scsi_periph_handle, vecs, pos,
|
||||
num_blocks, block_size, bytes_transferred, 10);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
update_capacity(das_device_info *device)
|
||||
{
|
||||
scsi_ccb *ccb;
|
||||
status_t res;
|
||||
|
||||
SHOW_FLOW0(3, "");
|
||||
|
||||
ccb = device->scsi->alloc_ccb(device->scsi_device);
|
||||
if (ccb == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
res = scsi_periph->check_capacity(device->scsi_periph_device, ccb);
|
||||
|
||||
device->scsi->free_ccb(ccb);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_geometry(das_handle_info *handle, void *buf, size_t len)
|
||||
{
|
||||
das_device_info *device = handle->device;
|
||||
device_geometry *geometry = (device_geometry *)buf;
|
||||
status_t res;
|
||||
|
||||
SHOW_FLOW0(3, "");
|
||||
|
||||
res = update_capacity(device);
|
||||
|
||||
if (res < B_OK)
|
||||
return res;
|
||||
|
||||
geometry->bytes_per_sector = device->block_size;
|
||||
geometry->sectors_per_track = 1;
|
||||
geometry->cylinder_count = device->capacity;
|
||||
geometry->head_count = 1;
|
||||
geometry->device_type = B_DISK;
|
||||
geometry->removable = device->removable;
|
||||
|
||||
// TBD: for all but CD-ROMs, read mode sense - medium type
|
||||
// (bit 7 of block device specific parameter for Optical Memory Block Device)
|
||||
// (same for Direct-Access Block Devices)
|
||||
// (same for write-once block devices)
|
||||
// (same for optical memory block devices)
|
||||
geometry->read_only = false;
|
||||
geometry->write_once = false;
|
||||
|
||||
SHOW_FLOW(3, "%ld, %ld, %ld, %ld, %d, %d, %d, %d",
|
||||
geometry->bytes_per_sector,
|
||||
geometry->sectors_per_track,
|
||||
geometry->cylinder_count,
|
||||
geometry->head_count,
|
||||
geometry->device_type,
|
||||
geometry->removable,
|
||||
geometry->read_only,
|
||||
geometry->write_once);
|
||||
|
||||
SHOW_FLOW0(3, "done");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
load_eject(das_device_info *device, bool load)
|
||||
{
|
||||
scsi_ccb *ccb;
|
||||
err_res res;
|
||||
|
||||
SHOW_FLOW0(0, "");
|
||||
|
||||
ccb = device->scsi->alloc_ccb(device->scsi_device);
|
||||
|
||||
res = scsi_periph->send_start_stop(device->scsi_periph_device,
|
||||
ccb, load, true);
|
||||
|
||||
device->scsi->free_ccb(ccb);
|
||||
|
||||
return res.error_code;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
synchronize_cache(das_device_info *device)
|
||||
{
|
||||
scsi_ccb *ccb;
|
||||
err_res res;
|
||||
|
||||
SHOW_FLOW0(0, "");
|
||||
|
||||
ccb = device->scsi->alloc_ccb(device->scsi_device);
|
||||
|
||||
res = scsi_periph->synchronize_cache(device->scsi_periph_device, ccb);
|
||||
|
||||
device->scsi->free_ccb(ccb);
|
||||
|
||||
return res.error_code;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
log2(uint32 x)
|
||||
{
|
||||
int y;
|
||||
|
||||
for (y = 31; y >= 0; --y)
|
||||
if (x == ((uint32)1 << y))
|
||||
break;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
das_set_capacity(das_device_info *device, uint64 capacity,
|
||||
uint32 block_size)
|
||||
{
|
||||
uint32 ld_block_size;
|
||||
|
||||
SHOW_FLOW(3, "device=%p, capacity=%Ld, block_size=%ld",
|
||||
device, capacity, block_size);
|
||||
|
||||
// get log2, if possible
|
||||
ld_block_size = log2(block_size);
|
||||
|
||||
if ((1UL << ld_block_size) != block_size)
|
||||
ld_block_size = 0;
|
||||
|
||||
device->capacity = capacity;
|
||||
device->block_size = block_size;
|
||||
|
||||
gBlockIO->set_media_params(device->block_io_device, block_size,
|
||||
ld_block_size, capacity);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
das_media_changed(das_device_info *device, scsi_ccb *request)
|
||||
{
|
||||
// do a capacity check
|
||||
// TBD: is this a good idea (e.g. if this is an empty CD)?
|
||||
scsi_periph->check_capacity(device->scsi_periph_device, request);
|
||||
}
|
||||
|
||||
|
||||
scsi_periph_callbacks callbacks = {
|
||||
(void (*)(periph_device_cookie, uint64, uint32))das_set_capacity,
|
||||
(void (*)(periph_device_cookie, scsi_ccb *))das_media_changed
|
||||
};
|
||||
|
||||
|
||||
static status_t
|
||||
das_ioctl(das_handle_info *handle, int op, void *buf, size_t len)
|
||||
{
|
||||
das_device_info *device = handle->device;
|
||||
status_t res;
|
||||
|
||||
SHOW_FLOW(4, "%d", op);
|
||||
|
||||
switch (op) {
|
||||
case B_GET_DEVICE_SIZE:
|
||||
res = update_capacity(device);
|
||||
if (res == B_OK)
|
||||
*(size_t *)buf = device->capacity * device->block_size;
|
||||
break;
|
||||
|
||||
case B_GET_GEOMETRY:
|
||||
res = get_geometry(handle, buf, len);
|
||||
break;
|
||||
|
||||
case B_GET_ICON:
|
||||
res = scsi_periph->get_icon(device->removable ? icon_type_floppy : icon_type_disk,
|
||||
(device_icon *)buf);
|
||||
break;
|
||||
|
||||
case B_EJECT_DEVICE:
|
||||
case B_SCSI_EJECT:
|
||||
res = load_eject(device, false);
|
||||
break;
|
||||
|
||||
case B_LOAD_MEDIA:
|
||||
res = load_eject(device, true);
|
||||
break;
|
||||
|
||||
case B_FLUSH_DRIVE_CACHE:
|
||||
res = synchronize_cache(device);
|
||||
break;
|
||||
|
||||
default:
|
||||
res = scsi_periph->ioctl(handle->scsi_periph_handle, op, buf, len);
|
||||
}
|
||||
|
||||
SHOW_FLOW(4, "%s", strerror(res));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static float
|
||||
das_supports_device(device_node *parent)
|
||||
{
|
||||
const char *bus;
|
||||
uint8 deviceType;
|
||||
|
||||
// make sure parent is really the SCSI bus manager
|
||||
if (pnp->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
|
||||
return -1;
|
||||
|
||||
if (strcmp(bus, "scsi"))
|
||||
return 0.0;
|
||||
|
||||
// check whether it's really a Direct Access Device
|
||||
if (pnp->get_attr_uint8(parent, SCSI_DEVICE_TYPE_ITEM, &deviceType, true)
|
||||
!= B_OK || deviceType != scsi_dev_direct_access)
|
||||
return 0.0;
|
||||
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
das_publish_device(void *_cookie)
|
||||
{
|
||||
das_device_info *device = (das_device_info *)_cookie;
|
||||
status_t status;
|
||||
char *name;
|
||||
|
||||
name = scsi_periph->compose_device_name(device->node, "disk/scsi");
|
||||
if (name == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
status = pnp->publish_device(device->node, name,
|
||||
B_BLOCK_IO_DEVICE_MODULE_NAME);
|
||||
|
||||
free(name);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
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[] = {
|
||||
{ SCSI_PERIPH_MODULE_NAME, (module_info **)&scsi_periph },
|
||||
{ B_BLOCK_IO_FOR_DRIVER_MODULE_NAME, (module_info **)&gBlockIO },
|
||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||
{}
|
||||
};
|
||||
|
||||
block_device_interface sSCSIDiskModule = {
|
||||
{
|
||||
{
|
||||
SCSI_DSK_MODULE_NAME,
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
|
||||
das_supports_device,
|
||||
das_device_added,
|
||||
das_init_device,
|
||||
das_uninit_device,
|
||||
das_publish_device,
|
||||
NULL, // rescan
|
||||
},
|
||||
|
||||
(void (*)(block_device_cookie *, block_io_device)) &das_set_device,
|
||||
(status_t (*)(block_device_cookie *, block_device_handle_cookie *))&das_open,
|
||||
(status_t (*)(block_device_handle_cookie)) &das_close,
|
||||
(status_t (*)(block_device_handle_cookie)) &das_free,
|
||||
|
||||
(status_t (*)(block_device_handle_cookie, const phys_vecs *,
|
||||
off_t, size_t, uint32, size_t *)) &das_read,
|
||||
(status_t (*)(block_device_handle_cookie, const phys_vecs *,
|
||||
off_t, size_t, uint32, size_t *)) &das_write,
|
||||
|
||||
(status_t (*)(block_device_handle_cookie, int, void *, size_t))&das_ioctl,
|
||||
};
|
||||
|
||||
module_info *modules[] = {
|
||||
(module_info *)&sSCSIDiskModule,
|
||||
NULL
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Peripheral driver to handle any kind of SCSI disks,
|
||||
i.e. hard disk and floopy disks (ZIP etc.)
|
||||
|
||||
Much work is done by scsi_periph and blkdev.
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_DSK_H
|
||||
#define _SCSI_DSK_H
|
||||
|
||||
#include <device_manager.h>
|
||||
|
||||
#define SCSI_DSK_MODULE_NAME "drivers/disk/scsi/scsi_dsk/driver_v1"
|
||||
|
||||
#endif /* _SCSI_DSK_H */
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Part of Open SCSI Disk Driver
|
||||
|
||||
SCSI Direct Access Storage Device Driver (aka SCSI Disk Driver)
|
||||
*/
|
||||
|
||||
#include <device_manager.h>
|
||||
#include "scsi_dsk.h"
|
||||
#include <scsi_periph.h>
|
||||
#include <block_io.h>
|
||||
|
||||
#define debug_level_flow 0
|
||||
#define debug_level_info 1
|
||||
#define debug_level_error 2
|
||||
|
||||
#define DEBUG_MSG_PREFIX "SCSI_DSK -- "
|
||||
|
||||
#include "wrapper.h"
|
||||
|
||||
|
||||
// must start as block_device_cookie
|
||||
typedef struct das_device_info {
|
||||
device_node *node;
|
||||
scsi_periph_device scsi_periph_device;
|
||||
scsi_device scsi_device;
|
||||
scsi_device_interface *scsi;
|
||||
block_io_device block_io_device;
|
||||
|
||||
uint64 capacity;
|
||||
uint32 block_size;
|
||||
|
||||
bool removable; // true, if device is removable
|
||||
} das_device_info;
|
||||
|
||||
typedef struct das_handle_info {
|
||||
scsi_periph_handle scsi_periph_handle;
|
||||
das_device_info *device;
|
||||
} das_handle_info;
|
||||
|
||||
extern scsi_periph_interface *scsi_periph;
|
||||
extern device_manager_info *pnp;
|
||||
extern scsi_periph_callbacks callbacks;
|
||||
extern block_io_for_driver_interface *gBlockIO;
|
||||
|
||||
|
||||
// device.c
|
||||
|
||||
status_t das_device_added(device_node *node);
|
||||
status_t das_init_device(device_node *node, void **cookie);
|
||||
void das_uninit_device(void *cookie);
|
||||
|
||||
|
||||
// scsi_dsk.c
|
||||
|
||||
status_t das_open(das_device_info *device, das_handle_info **handle_out);
|
||||
status_t das_close(das_handle_info *handle);
|
||||
status_t das_free(das_handle_info *handle);
|
||||
|
||||
void das_set_capacity(das_device_info *device, uint64 capacity,
|
||||
uint32 block_size);
|
@ -1,90 +0,0 @@
|
||||
#ifndef _WRAPPER_H
|
||||
#define _WRAPPER_H
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <lock.h>
|
||||
|
||||
|
||||
// benaphores
|
||||
|
||||
#define INIT_BEN(x, prefix) (mutex_init_etc(x, prefix, MUTEX_FLAG_CLONE_NAME), \
|
||||
B_OK)
|
||||
#define DELETE_BEN(x) mutex_destroy(x)
|
||||
#define ACQUIRE_BEN(x) mutex_lock(x)
|
||||
#define RELEASE_BEN(x) mutex_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 1
|
||||
#endif
|
||||
|
||||
#ifndef debug_level_info
|
||||
# define debug_level_info 2
|
||||
#endif
|
||||
|
||||
#ifndef debug_level_error
|
||||
# define debug_level_error 3
|
||||
#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_no_syslog( "%s%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_no_syslog( "%s%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%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%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%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%s: "format"\n", FUNC_NAME); DEBUG_WAIT_ERROR \
|
||||
}} while( 0 )
|
||||
|
||||
#endif /* _BENAPHORE_H */
|
@ -571,7 +571,7 @@ struct device_module_info sBlockIOModule = {
|
||||
(status_t (*)(void *, off_t, const void *, size_t *))block_io_write,
|
||||
NULL, // io
|
||||
|
||||
(status_t (*)(void *, int32, void *, size_t))block_io_ioctl,
|
||||
(status_t (*)(void *, uint32, void *, size_t))block_io_ioctl,
|
||||
|
||||
NULL, // select
|
||||
NULL, // deselect
|
||||
|
@ -53,7 +53,7 @@ typedef struct block_io_device_info {
|
||||
// file handle info
|
||||
typedef struct block_io_handle_info {
|
||||
block_io_device_info *device;
|
||||
block_device_handle_cookie cookie;
|
||||
block_device_handle_cookie *cookie;
|
||||
} block_io_handle_info;
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user