diff --git a/headers/os/drivers/bus/SCSI.h b/headers/os/drivers/bus/SCSI.h index e4b9384d70..2487c244e4 100644 --- a/headers/os/drivers/bus/SCSI.h +++ b/headers/os/drivers/bus/SCSI.h @@ -1,13 +1,13 @@ /* + * Copyright 2004-2006, Haiku, Inc. All RightsReserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved. + * * Distributed under the terms of the MIT License. */ -#ifndef __SCSI_BUSMANAGER_H__ -#define __SCSI_BUSMANAGER_H__ +#ifndef _SCSI_BUSMANAGER_H_ +#define _SCSI_BUSMANAGER_H_ /* - Part of Open SCSI bus manager - SCSI bus manager interface The bus manager interface is _based_ on CAM, but I've modified it because :- @@ -315,6 +315,8 @@ typedef struct scsi_device_interface { uchar (*reset_device)(scsi_device device); // terminate request uchar (*term_io)(scsi_ccb *ccb_to_terminate); + + status_t (*ioctl)(scsi_device device, uint32 op, void *buffer, size_t length); } scsi_device_interface; #define SCSI_DEVICE_MODULE_NAME "bus_managers/scsi/driver/v1" @@ -439,8 +441,8 @@ typedef struct scsi_sim_interface { // get restrictions of one device // (used for non-SCSI transport protocols and bug fixes) - void (*get_restrictions)( - scsi_sim_cookie cookie, + void (*get_restrictions)( + scsi_sim_cookie cookie, uchar target_id, // target id bool *is_atapi, // set to true if this is an ATAPI device that // needs some commands emulated @@ -450,7 +452,9 @@ typedef struct scsi_sim_interface { uint32 *max_blocks ); // maximum number of blocks per transfer if > 0; // used for buggy devices that cannot handle // large transfers (read: ATAPI ZIP drives) + + status_t (*ioctl)(scsi_sim_cookie, uint8 targetID, uint32 op, void *buffer, size_t length); } scsi_sim_interface; -#endif /* __SCSI_BUSMANAGER_H__ */ +#endif /* _SCSI_BUSMANAGER_H_ */ diff --git a/src/add-ons/kernel/bus_managers/ide/ide_device_infoblock.h b/src/add-ons/kernel/bus_managers/ide/ide_device_infoblock.h index 67f8788f37..b2a799dd39 100644 --- a/src/add-ons/kernel/bus_managers/ide/ide_device_infoblock.h +++ b/src/add-ons/kernel/bus_managers/ide/ide_device_infoblock.h @@ -1,24 +1,29 @@ /* -** Copyright 2002/03, Thomas Kurschel. All rights reserved. -** Distributed under the terms of the OpenBeOS License. -*/ + * Copyright 2004-2006, Haiku, Inc. All RightsReserved. + * Copyright 2002/03, Thomas Kurschel. All rights reserved. + * + * Distributed under the terms of the MIT License. + */ +#ifndef _IDE_DEVICE_INFOBLOCK_H_ +#define _IDE_DEVICE_INFOBLOCK_H_ /* - Part of Open IDE bus manager - Definition of response to IDE_CMD_IDENTIFY_DEVICE or IDE_CMD_IDENTIFY_PACKET_DEVICE - + When a new entry is inserted, add its offset in hex and its index in decimal as a remark. Without that, you have a rough time when you messed up the offsets. */ -#ifndef __IDE_DEVICE_INFOBLOCK_H__ -#define __IDE_DEVICE_INFOBLOCK_H__ #include + +#define IDE_GET_INFO_BLOCK 0x2710 +#define IDE_GET_STATUS 0x2711 + + // must be 512 bytes!!! typedef struct tagdevice_infoblock { union { // 0 general configuration @@ -181,5 +186,11 @@ typedef struct tagdevice_infoblock { uint16 dummy14[128]; // 100 (128) } ide_device_infoblock; +typedef struct ide_status { + uint8 _reserved; + uint8 dma_status; + uint8 pio_mode; + uint8 dma_mode; +} ide_status; -#endif +#endif /* _IDE_DEVICE_INFOBLOCK_H_ */ diff --git a/src/add-ons/kernel/bus_managers/ide/ide_sim.c b/src/add-ons/kernel/bus_managers/ide/ide_sim.c index fc3e2f5b0d..e2bb98ed56 100644 --- a/src/add-ons/kernel/bus_managers/ide/ide_sim.c +++ b/src/add-ons/kernel/bus_managers/ide/ide_sim.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved. * * Distributed under the terms of the MIT License. @@ -26,6 +26,8 @@ #include "ide_sim.h" #include +#include + #include #include #include @@ -546,7 +548,8 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie) { device_node_handle parent; ide_bus_info *bus; - int res; + bool dmaDisabled = false; + status_t status; SHOW_FLOW0(3, ""); @@ -586,13 +589,13 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie) bus->timer.bus = bus; bus->synced_pc_list = NULL; - if ((res = scsi->alloc_dpc(&bus->irq_dpc)) < 0) + if ((status = scsi->alloc_dpc(&bus->irq_dpc)) < B_OK) goto err1; bus->active_device = NULL; bus->sync_wait_sem = create_sem(0, "ide_sync_wait"); if (bus->sync_wait_sem < 0) { - res = bus->sync_wait_sem; + status = bus->sync_wait_sem; goto err2; } @@ -600,28 +603,41 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie) bus->scan_device_sem = create_sem(0, "ide_scan_finished"); if (bus->scan_device_sem < 0) { - res = bus->scan_device_sem; + status = bus->scan_device_sem; goto err3; } - res = INIT_BEN(&bus->status_report_ben, "ide_status_report"); - if (res < 0) + status = INIT_BEN(&bus->status_report_ben, "ide_status_report"); + if (status < B_OK) goto err4; + { + // check if safemode settings disable DMA + void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); + if (settings != NULL) { + dmaDisabled = get_driver_boolean_parameter(settings, B_SAFEMODE_DISABLE_IDE_DMA, + false, false); + unload_driver_settings(settings); + } + } + bus->first_device = NULL; // read restrictions of controller if (pnp->get_attr_uint8(node, IDE_CONTROLLER_MAX_DEVICES_ITEM, - &bus->max_devices, true) != B_OK) + &bus->max_devices, true) != B_OK) { // per default, 2 devices are supported per node bus->max_devices = 2; + } bus->max_devices = min(bus->max_devices, 2); - if (pnp->get_attr_uint8(node, IDE_CONTROLLER_CAN_DMA_ITEM, &bus->can_DMA, true) != B_OK) + if (dmaDisabled + || pnp->get_attr_uint8(node, IDE_CONTROLLER_CAN_DMA_ITEM, &bus->can_DMA, true) != B_OK) { // per default, no dma support bus->can_DMA = false; + } SHOW_FLOW(2, "can_dma: %d", bus->can_DMA); @@ -643,19 +659,17 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie) parent = pnp->get_parent(node); - res = pnp->init_driver(parent, bus, - (driver_module_info **)&bus->controller, - (void **)&bus->channel); + status = pnp->init_driver(parent, bus, (driver_module_info **)&bus->controller, + (void **)&bus->channel); pnp->put_device_node(parent); - if (res != B_OK) + if (status != B_OK) goto err5; *cookie = bus; // detect devices sim_scan_bus(bus); - return B_OK; err5: @@ -675,7 +689,7 @@ err: #endif free(bus); - return res; + return status; } @@ -766,6 +780,47 @@ ide_sim_get_restrictions(ide_bus_info *bus, uchar target_id, } +static status_t +ide_sim_ioctl(ide_bus_info *bus, uint8 targetID, uint32 op, void *buffer, size_t length) +{ + ide_device_info *device = bus->devices[targetID]; + + // We currently only support IDE_GET_INFO_BLOCK + switch (op) { + case IDE_GET_INFO_BLOCK: + // we already have the info block, just copy it + memcpy(buffer, &device->infoblock, + min(sizeof(device->infoblock), length)); + return B_OK; + + case IDE_GET_STATUS: + { + // TODO: have our own structure and fill it with some useful stuff + ide_status status; + if (device->DMA_enabled) + status.dma_status = 1; + else if (device->DMA_supported) { + if (device->DMA_failures > 0) + status.dma_status = 6; + else if (device->bus->can_DMA) + status.dma_status = 2; + else + status.dma_status = 4; + } else + status.dma_status = 2; + + status.pio_mode = 0; + status.dma_mode = 0; + + memcpy(buffer, &status, min(sizeof(status), length)); + return B_OK; + } + } + + return B_BAD_VALUE; +} + + static status_t std_ops(int32 op, ...) { @@ -801,7 +856,7 @@ scsi_sim_interface ide_sim_module = { (status_t (*)(void *) ) ide_sim_uninit_bus, (void (*)(device_node_handle, void *)) ide_sim_bus_removed }, - + (void (*)(scsi_sim_cookie, scsi_ccb *)) sim_scsi_io, (uchar (*)(scsi_sim_cookie, scsi_ccb *)) sim_abort, (uchar (*)(scsi_sim_cookie, uchar, uchar)) sim_reset_device, @@ -812,5 +867,7 @@ scsi_sim_interface ide_sim_module = { (uchar (*)(scsi_sim_cookie)) sim_reset_bus, (void (*)(scsi_sim_cookie, uchar, - bool*, bool *, uint32 *)) ide_sim_get_restrictions + bool*, bool *, uint32 *)) ide_sim_get_restrictions, + + (status_t (*)(scsi_sim_cookie, uint8, uint32, void *, size_t))ide_sim_ioctl, }; diff --git a/src/add-ons/kernel/bus_managers/scsi/devices.c b/src/add-ons/kernel/bus_managers/scsi/devices.c index 27d244554b..b4f20f7b72 100644 --- a/src/add-ons/kernel/bus_managers/scsi/devices.c +++ b/src/add-ons/kernel/bus_managers/scsi/devices.c @@ -1,11 +1,11 @@ /* + * Copyright 2004-2006, Haiku, Inc. All RightsReserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved. + * * Distributed under the terms of the MIT License. */ /* - Part of Open SCSI bus manager - Device node layer. When a SCSI bus is registered, this layer scans for SCSI devices @@ -516,6 +516,18 @@ scsi_reset_device(scsi_device_info *device) } +static status_t +scsi_ioctl(scsi_device_info *device, uint32 op, void *buffer, size_t length) +{ + if (device->bus->interface->ioctl != NULL) { + return device->bus->interface->ioctl(device->bus->sim_cookie, + device->target_id, op, buffer, length); + } + + return B_BAD_VALUE; +} + + static status_t std_ops(int32 op, ...) { @@ -559,5 +571,6 @@ scsi_device_interface scsi_device_module = { scsi_sync_io, scsi_abort, scsi_reset_device, - scsi_term_io + scsi_term_io, + scsi_ioctl, }; diff --git a/src/add-ons/kernel/generic/scsi_periph/io.c b/src/add-ons/kernel/generic/scsi_periph/io.c index faab005396..226e5f35b0 100644 --- a/src/add-ons/kernel/generic/scsi_periph/io.c +++ b/src/add-ons/kernel/generic/scsi_periph/io.c @@ -1,11 +1,12 @@ /* -** Copyright 2002/03, Thomas Kurschel. All rights reserved. -** Distributed under the terms of the Haiku License. -*/ + * Copyright 2004-2006, Haiku, Inc. All RightsReserved. + * 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. */ @@ -301,6 +302,11 @@ periph_ioctl(scsi_periph_handle_info *handle, int op, void *buffer, size_t lengt return raw_command(handle->device, buffer); default: + if (handle->device->scsi->ioctl != NULL) { + return handle->device->scsi->ioctl(handle->device->scsi_device, + op, buffer, length); + } + SHOW_ERROR(4, "Unknown ioctl: %x", op); return B_BAD_VALUE; }