#ifndef VIRTIO_SCSI_PRIVATE_H
#define VIRTIO_SCSI_PRIVATE_H
#include <bus/SCSI.h>
#include <condition_variable.h>
#include <lock.h>
#include <scsi_cmds.h>
#include <virtio.h>
#include "virtio_scsi.h"
#ifdef TRACE_VIRTIO_SCSI
# define TRACE(x...) dprintf("virtio_scsi: " x)
#else
# define TRACE(x...) ;
#endif
#define ERROR(x...) dprintf("\33[33mvirtio_scsi:\33[0m " x)
#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
extern device_manager_info* gDeviceManager;
extern scsi_for_sim_interface *gSCSI;
bool copy_sg_data(scsi_ccb *ccb, uint offset, uint allocationLength,
void *buffer, int size, bool toBuffer);
void swap_words(void *data, size_t size);
#define VIRTIO_SCSI_STANDARD_TIMEOUT 10 * 1000 * 1000
#define VIRTIO_SCSI_INITIATOR_ID 7
#define VIRTIO_SCSI_NUM_EVENTS 4
class VirtioSCSIRequest;
class VirtioSCSIController {
public:
VirtioSCSIController(device_node* node);
~VirtioSCSIController();
status_t InitCheck();
void SetBus(scsi_bus bus);
scsi_bus Bus() const { return fBus; }
void PathInquiry(scsi_path_inquiry* info);
void GetRestrictions(uint8 targetID, bool* isATAPI,
bool* noAutoSense, uint32* maxBlocks);
uchar ResetDevice(uchar targetID, uchar targetLUN);
status_t ExecuteRequest(scsi_ccb* request);
uchar AbortRequest(scsi_ccb* request);
uchar TerminateRequest(scsi_ccb* request);
status_t Control(uint8 targetID, uint32 op,
void* buffer, size_t length);
private:
static void _RequestCallback(void* driverCookie,
void *cookie);
void _RequestInterrupt();
static void _EventCallback(void *driverCookie,
void *cookie);
void _EventInterrupt(
struct virtio_scsi_event* event);
static void _RescanChildBus(void *cookie);
void _SubmitEvent(uint32 event);
device_node* fNode;
scsi_bus fBus;
virtio_device_interface* fVirtio;
virtio_device* fVirtioDevice;
status_t fStatus;
struct virtio_scsi_config fConfig;
uint64 fFeatures;
::virtio_queue fControlVirtioQueue;
::virtio_queue fEventVirtioQueue;
::virtio_queue fRequestVirtioQueue;
area_id fArea;
struct virtio_scsi_event* fEvents;
VirtioSCSIRequest* fRequest;
int32 fCurrentRequest;
ConditionVariable fInterruptCondition;
scsi_dpc_cookie fEventDPC;
struct virtio_scsi_event fEventBuffers[VIRTIO_SCSI_NUM_EVENTS];
};
class VirtioSCSIRequest {
public:
VirtioSCSIRequest(bool hasLock);
~VirtioSCSIRequest();
void SetStatus(uint8 status);
uint8 Status() const { return fStatus; }
void SetTimeout(bigtime_t timeout);
bigtime_t Timeout() const { return fTimeout; }
bool HasSense() {
return (fResponse->sense_len > 0); }
void SetIsWrite(bool isWrite);
bool IsWrite() const { return fIsWrite; }
void SetBytesLeft(uint32 bytesLeft);
size_t* BytesLeft() { return &fBytesLeft; }
bool HasData() const
{ return fCCB->data_length > 0; }
status_t Finish(bool resubmit);
void Abort();
status_t Start(scsi_ccb *ccb);
scsi_ccb* CCB() { return fCCB; }
void RequestSense();
void FillRequest(uint32 inCount, uint32 outCount,
physical_entry *entries);
private:
void _FillSense(scsi_sense *sense);
uchar _ResponseStatus();
mutex fLock;
bool fHasLock;
uint8 fStatus;
bigtime_t fTimeout;
size_t fBytesLeft;
bool fIsWrite;
scsi_ccb* fCCB;
void* fBuffer;
struct virtio_scsi_cmd_req *fRequest;
struct virtio_scsi_cmd_resp *fResponse;
};
#endif