/*
* Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
* Copyright 2008, Marcus Overhagen.
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2002-2003, Thomas Kurschel.
*
* Distributed under the terms of the MIT License.
*/
#include "ATAPrivate.h"
scsi_for_sim_interface *gSCSIModule = NULL;
device_manager_info *gDeviceManager = NULL;
static status_t
ata_sim_init_bus(device_node *node, void **cookie)
{
ATAChannel *channel = new(std::nothrow) ATAChannel(node);
if (channel == NULL)
return B_NO_MEMORY;
status_t result = channel->InitCheck();
if (result != B_OK) {
TRACE_ERROR("failed to set up ata channel object\n");
return result;
}
*cookie = channel;
return B_OK;
}
static void
ata_sim_uninit_bus(void *cookie)
{
ATAChannel *channel = (ATAChannel *)cookie;
delete channel;
}
static void
ata_sim_bus_removed(void *cookie)
{
ATAChannel *channel = (ATAChannel *)cookie;
if (channel->Bus() != NULL) {
gSCSIModule->block_bus(channel->Bus());
channel->SetBus(NULL);
}
}
static void
ata_sim_set_scsi_bus(scsi_sim_cookie cookie, scsi_bus bus)
{
ATAChannel *channel = (ATAChannel *)cookie;
channel->SetBus(bus);
channel->ScanBus();
}
static void
ata_sim_scsi_io(scsi_sim_cookie cookie, scsi_ccb *ccb)
{
ATAChannel *channel = (ATAChannel *)cookie;
if (channel->Bus() == NULL) {
ccb->subsys_status = SCSI_NO_HBA;
gSCSIModule->finished(ccb, 1);
return;
}
if (channel->ExecuteIO(ccb) == B_BUSY)
gSCSIModule->requeue(ccb, true);
}
static uchar
ata_sim_abort(scsi_sim_cookie cookie, scsi_ccb *ccb)
{
ATAChannel *channel = (ATAChannel *)cookie;
if (channel->Bus() == NULL)
return SCSI_NO_HBA;
// aborting individual commands is not possible
return SCSI_REQ_CMP;
}
static uchar
ata_sim_reset_device(scsi_sim_cookie cookie, uchar targetId, uchar targetLun)
{
ATAChannel *channel = (ATAChannel *)cookie;
if (channel->Bus() == NULL)
return SCSI_NO_HBA;
// TODO: implement
return SCSI_REQ_INVALID;
}
static uchar
ata_sim_term_io(scsi_sim_cookie cookie, scsi_ccb *ccb)
{
ATAChannel *channel = (ATAChannel *)cookie;
if (channel->Bus() == NULL)
return SCSI_NO_HBA;
// we don't terminate commands, ignore
return SCSI_REQ_CMP;
}
static uchar
ata_sim_path_inquiry(scsi_sim_cookie cookie, scsi_path_inquiry *info)
{
ATAChannel *channel = (ATAChannel *)cookie;
if (channel->Bus() == NULL)
return SCSI_NO_HBA;
channel->PathInquiry(info);
return SCSI_REQ_CMP;
}
static uchar
ata_sim_rescan_bus(scsi_sim_cookie cookie)
{
// TODO: implement
return SCSI_REQ_CMP;
}
static uchar
ata_sim_reset_bus(scsi_sim_cookie cookie)
{
ATAChannel *channel = (ATAChannel *)cookie;
if (channel->Bus() == NULL)
return SCSI_NO_HBA;
//channel->Reset();
panic("asking for trouble");
return SCSI_REQ_CMP;
}
static void
ata_sim_get_restrictions(scsi_sim_cookie cookie, uchar targetID,
bool *isATAPI, bool *noAutoSense, uint32 *maxBlocks)
{
ATAChannel *channel = (ATAChannel *)cookie;
channel->GetRestrictions(targetID, isATAPI, noAutoSense, maxBlocks);
}
static status_t
ata_sim_control(scsi_sim_cookie cookie, uchar targetID, uint32 op, void *buffer,
size_t length)
{
ATAChannel *channel = (ATAChannel *)cookie;
return channel->Control(targetID, op, buffer, length);
}
status_t
ata_channel_added(device_node *parent)
{
const char *controllerName;
if (gDeviceManager->get_attr_string(parent,
ATA_CONTROLLER_CONTROLLER_NAME_ITEM, &controllerName, true) != B_OK) {
TRACE_ERROR("controller name missing\n");
return B_ERROR;
}
int32 channelID = gDeviceManager->create_id(ATA_CHANNEL_ID_GENERATOR);
if (channelID < 0) {
TRACE_ERROR("out of channel ids\n");
return B_ERROR;
}
device_attr attributes[] = {
{
B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
{ string: SCSI_FOR_SIM_MODULE_NAME }
},
{
SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
{ string: controllerName }
},
// maximum number of blocks per transmission:
// - ATAPI uses packets, i.e. normal SCSI limits apply
// but I'm not sure about controller restrictions
// - ATA allows up to 256 blocks for LBA28 and 65535 for LBA48
// to fix specific drive bugs use ATAChannel::GetRestrictions()
{ B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { ui32: 0xffff } },
{ ATA_CHANNEL_ID_ITEM, B_UINT32_TYPE, { ui32: (uint32)channelID } },
{ NULL }
};
return gDeviceManager->register_node(parent, ATA_SIM_MODULE_NAME,
attributes, NULL, NULL);
}
status_t
ata_interrupt_handler(void *cookie, uint8 status)
{
ATAChannel *channel = (ATAChannel *)cookie;
return channel->Interrupt(status);
}
static status_t
std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
default:
break;
}
return B_ERROR;
}
scsi_sim_interface ata_sim_module = {
{
{
ATA_SIM_MODULE_NAME,
0,
std_ops
},
NULL, // supported devices
NULL, // register node
ata_sim_init_bus,
ata_sim_uninit_bus,
NULL, // register child devices
NULL, // rescan
ata_sim_bus_removed,
NULL, // suspend
NULL, // resume
},
ata_sim_set_scsi_bus,
ata_sim_scsi_io,
ata_sim_abort,
ata_sim_reset_device,
ata_sim_term_io,
ata_sim_path_inquiry,
ata_sim_rescan_bus,
ata_sim_reset_bus,
ata_sim_get_restrictions,
ata_sim_control
};
ata_for_controller_interface ata_for_controller_module = {
{
{
ATA_FOR_CONTROLLER_MODULE_NAME,
0,
&std_ops
},
NULL, // supported devices
ata_channel_added,
NULL,
NULL,
NULL
},
ata_interrupt_handler
};
module_dependency module_dependencies[] = {
{ SCSI_FOR_SIM_MODULE_NAME, (module_info **)&gSCSIModule },
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
{}
};
module_info *modules[] = {
(module_info *)&ata_for_controller_module,
(module_info *)&ata_sim_module,
NULL
};
↑ V773 The function was exited without releasing the 'channel' pointer. A memory leak is possible.