2009-07-13 23:01:31 +00:00
/*
*
* Copyright ( c ) 2009 , Microsoft Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . , 59 Temple
* Place - Suite 330 , Boston , MA 02111 - 1307 USA .
*
* Authors :
* Haiyang Zhang < haiyangz @ microsoft . com >
* Hank Janssen < hjanssen @ microsoft . com >
*
*/
2009-07-14 22:08:20 +00:00
# include <linux/kernel.h>
2009-07-15 18:06:01 +00:00
# include <linux/string.h>
# include <linux/mm.h>
2009-07-16 18:50:41 +00:00
# include <linux/delay.h>
2009-07-14 17:18:50 +00:00
# include "include/logging.h"
2009-07-13 23:01:31 +00:00
2009-07-14 17:18:50 +00:00
# include "include/StorVscApi.h"
# include "include/VmbusPacketFormat.h"
# include "include/vstorage.h"
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
/* #defines */
/* Data types */
2009-07-13 23:01:31 +00:00
typedef struct _STORVSC_REQUEST_EXTENSION {
2009-07-27 20:47:24 +00:00
/* LIST_ENTRY ListEntry; */
2009-07-13 23:01:31 +00:00
2009-07-29 12:10:19 +00:00
struct hv_storvsc_request * Request ;
2009-07-28 15:32:53 +00:00
struct hv_device * Device ;
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
/* Synchronize the request/response if needed */
2009-07-28 17:46:24 +00:00
struct osd_waitevent * WaitEvent ;
2009-07-13 23:01:31 +00:00
VSTOR_PACKET VStorPacket ;
} STORVSC_REQUEST_EXTENSION ;
2009-07-27 20:47:24 +00:00
/* A storvsc device is a device object that contains a vmbus channel */
2009-07-13 23:01:31 +00:00
typedef struct _STORVSC_DEVICE {
2009-07-28 15:32:53 +00:00
struct hv_device * Device ;
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
int RefCount ; /* 0 indicates the device is being destroyed */
2009-07-13 23:01:31 +00:00
int NumOutstandingRequests ;
2009-07-27 20:47:24 +00:00
/*
* Each unique Port / Path / Target represents 1 channel ie scsi
* controller . In reality , the pathid , targetid is always 0
* and the port is set by us
*/
2009-07-14 22:13:46 +00:00
unsigned int PortNumber ;
2009-07-14 22:10:26 +00:00
unsigned char PathId ;
unsigned char TargetId ;
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
/* LIST_ENTRY OutstandingRequestList; */
/* HANDLE OutstandingRequestLock; */
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
/* Used for vsc/vsp channel reset process */
2009-07-13 23:01:31 +00:00
STORVSC_REQUEST_EXTENSION InitRequest ;
STORVSC_REQUEST_EXTENSION ResetRequest ;
} STORVSC_DEVICE ;
2009-07-27 20:47:24 +00:00
/* Globals */
2009-07-13 23:01:31 +00:00
static const char * gDriverName = " storvsc " ;
2009-07-27 20:47:24 +00:00
/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
2009-07-13 23:01:31 +00:00
static const GUID gStorVscDeviceType = {
. Data = { 0xd9 , 0x63 , 0x61 , 0xba , 0xa1 , 0x04 , 0x29 , 0x4d , 0xb6 , 0x05 , 0x72 , 0xe2 , 0xff , 0xb1 , 0xdc , 0x7f }
} ;
2009-07-27 20:47:24 +00:00
/* Internal routines */
2009-07-13 23:01:31 +00:00
static int
StorVscOnDeviceAdd (
2009-07-28 15:32:53 +00:00
struct hv_device * Device ,
2009-07-13 23:01:31 +00:00
void * AdditionalInfo
) ;
static int
StorVscOnDeviceRemove (
2009-07-28 15:32:53 +00:00
struct hv_device * Device
2009-07-13 23:01:31 +00:00
) ;
static int
StorVscOnIORequest (
2009-07-28 15:32:53 +00:00
struct hv_device * Device ,
2009-07-29 12:10:19 +00:00
struct hv_storvsc_request * Request
2009-07-13 23:01:31 +00:00
) ;
static int
StorVscOnHostReset (
2009-07-28 15:32:53 +00:00
struct hv_device * Device
2009-07-13 23:01:31 +00:00
) ;
static void
StorVscOnCleanup (
2009-07-29 12:09:45 +00:00
struct hv_driver * Device
2009-07-13 23:01:31 +00:00
) ;
static void
StorVscOnChannelCallback (
2009-07-14 22:06:28 +00:00
void * Context
2009-07-13 23:01:31 +00:00
) ;
static void
StorVscOnIOCompletion (
2009-07-28 15:32:53 +00:00
struct hv_device * Device ,
2009-07-13 23:01:31 +00:00
VSTOR_PACKET * VStorPacket ,
STORVSC_REQUEST_EXTENSION * RequestExt
) ;
static void
StorVscOnReceive (
2009-07-28 15:32:53 +00:00
struct hv_device * Device ,
2009-07-13 23:01:31 +00:00
VSTOR_PACKET * VStorPacket ,
STORVSC_REQUEST_EXTENSION * RequestExt
) ;
static int
StorVscConnectToVsp (
2009-07-28 15:32:53 +00:00
struct hv_device * Device
2009-07-13 23:01:31 +00:00
) ;
2009-07-28 15:32:53 +00:00
static inline STORVSC_DEVICE * AllocStorDevice ( struct hv_device * Device )
2009-07-13 23:01:31 +00:00
{
STORVSC_DEVICE * storDevice ;
2009-07-15 19:47:43 +00:00
storDevice = kzalloc ( sizeof ( STORVSC_DEVICE ) , GFP_KERNEL ) ;
2009-07-13 23:01:31 +00:00
if ( ! storDevice )
return NULL ;
2009-07-27 20:47:24 +00:00
/* Set to 2 to allow both inbound and outbound traffics */
/* (ie GetStorDevice() and MustGetStorDevice()) to proceed. */
2009-07-13 23:01:31 +00:00
InterlockedCompareExchange ( & storDevice - > RefCount , 2 , 0 ) ;
storDevice - > Device = Device ;
Device - > Extension = storDevice ;
return storDevice ;
}
static inline void FreeStorDevice ( STORVSC_DEVICE * Device )
{
ASSERT ( Device - > RefCount = = 0 ) ;
2009-07-15 19:48:29 +00:00
kfree ( Device ) ;
2009-07-13 23:01:31 +00:00
}
2009-07-27 20:47:24 +00:00
/* Get the stordevice object iff exists and its refcount > 1 */
2009-07-28 15:32:53 +00:00
static inline STORVSC_DEVICE * GetStorDevice ( struct hv_device * Device )
2009-07-13 23:01:31 +00:00
{
STORVSC_DEVICE * storDevice ;
storDevice = ( STORVSC_DEVICE * ) Device - > Extension ;
if ( storDevice & & storDevice - > RefCount > 1 )
{
InterlockedIncrement ( & storDevice - > RefCount ) ;
}
else
{
storDevice = NULL ;
}
return storDevice ;
}
2009-07-27 20:47:24 +00:00
/* Get the stordevice object iff exists and its refcount > 0 */
2009-07-28 15:32:53 +00:00
static inline STORVSC_DEVICE * MustGetStorDevice ( struct hv_device * Device )
2009-07-13 23:01:31 +00:00
{
STORVSC_DEVICE * storDevice ;
storDevice = ( STORVSC_DEVICE * ) Device - > Extension ;
if ( storDevice & & storDevice - > RefCount )
{
InterlockedIncrement ( & storDevice - > RefCount ) ;
}
else
{
storDevice = NULL ;
}
return storDevice ;
}
2009-07-28 15:32:53 +00:00
static inline void PutStorDevice ( struct hv_device * Device )
2009-07-13 23:01:31 +00:00
{
STORVSC_DEVICE * storDevice ;
storDevice = ( STORVSC_DEVICE * ) Device - > Extension ;
ASSERT ( storDevice ) ;
InterlockedDecrement ( & storDevice - > RefCount ) ;
ASSERT ( storDevice - > RefCount ) ;
}
2009-07-27 20:47:24 +00:00
/* Drop ref count to 1 to effectively disable GetStorDevice() */
2009-07-28 15:32:53 +00:00
static inline STORVSC_DEVICE * ReleaseStorDevice ( struct hv_device * Device )
2009-07-13 23:01:31 +00:00
{
STORVSC_DEVICE * storDevice ;
storDevice = ( STORVSC_DEVICE * ) Device - > Extension ;
ASSERT ( storDevice ) ;
2009-07-27 20:47:24 +00:00
/* Busy wait until the ref drop to 2, then set it to 1 */
2009-07-13 23:01:31 +00:00
while ( InterlockedCompareExchange ( & storDevice - > RefCount , 1 , 2 ) ! = 2 )
{
2009-07-16 18:50:41 +00:00
udelay ( 100 ) ;
2009-07-13 23:01:31 +00:00
}
return storDevice ;
}
2009-07-27 20:47:24 +00:00
/* Drop ref count to 0. No one can use StorDevice object. */
2009-07-28 15:32:53 +00:00
static inline STORVSC_DEVICE * FinalReleaseStorDevice ( struct hv_device * Device )
2009-07-13 23:01:31 +00:00
{
STORVSC_DEVICE * storDevice ;
storDevice = ( STORVSC_DEVICE * ) Device - > Extension ;
ASSERT ( storDevice ) ;
2009-07-27 20:47:24 +00:00
/* Busy wait until the ref drop to 1, then set it to 0 */
2009-07-13 23:01:31 +00:00
while ( InterlockedCompareExchange ( & storDevice - > RefCount , 0 , 1 ) ! = 1 )
{
2009-07-16 18:50:41 +00:00
udelay ( 100 ) ;
2009-07-13 23:01:31 +00:00
}
Device - > Extension = NULL ;
return storDevice ;
}
/*++;
Name :
StorVscInitialize ( )
Description :
Main entry point
- - */
int
StorVscInitialize (
2009-07-29 12:09:45 +00:00
struct hv_driver * Driver
2009-07-13 23:01:31 +00:00
)
{
STORVSC_DRIVER_OBJECT * storDriver = ( STORVSC_DRIVER_OBJECT * ) Driver ;
int ret = 0 ;
DPRINT_ENTER ( STORVSC ) ;
2009-07-28 23:18:05 +00:00
DPRINT_DBG ( STORVSC , " sizeof(STORVSC_REQUEST)=%zd sizeof(STORVSC_REQUEST_EXTENSION)=%zd sizeof(VSTOR_PACKET)=%zd, sizeof(VMSCSI_REQUEST)=%zd " ,
2009-07-29 12:10:19 +00:00
sizeof ( struct hv_storvsc_request ) , sizeof ( STORVSC_REQUEST_EXTENSION ) , sizeof ( VSTOR_PACKET ) , sizeof ( VMSCSI_REQUEST ) ) ;
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
/* Make sure we are at least 2 pages since 1 page is used for control */
2009-07-13 23:01:31 +00:00
ASSERT ( storDriver - > RingBufferSize > = ( PAGE_SIZE < < 1 ) ) ;
Driver - > name = gDriverName ;
memcpy ( & Driver - > deviceType , & gStorVscDeviceType , sizeof ( GUID ) ) ;
storDriver - > RequestExtSize = sizeof ( STORVSC_REQUEST_EXTENSION ) ;
2009-07-27 20:47:24 +00:00
/*
* Divide the ring buffer data size ( which is 1 page less
* than the ring buffer size since that page is reserved for
* the ring buffer indices ) by the max request size ( which is
* VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER + VSTOR_PACKET + u64 )
*/
2009-07-13 23:01:31 +00:00
storDriver - > MaxOutstandingRequestsPerChannel =
2009-07-14 22:10:26 +00:00
( ( storDriver - > RingBufferSize - PAGE_SIZE ) / ALIGN_UP ( MAX_MULTIPAGE_BUFFER_PACKET + sizeof ( VSTOR_PACKET ) + sizeof ( u64 ) , sizeof ( u64 ) ) ) ;
2009-07-13 23:01:31 +00:00
DPRINT_INFO ( STORVSC , " max io %u, currently %u \n " , storDriver - > MaxOutstandingRequestsPerChannel , STORVSC_MAX_IO_REQUESTS ) ;
2009-07-27 20:47:24 +00:00
/* Setup the dispatch table */
2009-07-13 23:01:31 +00:00
storDriver - > Base . OnDeviceAdd = StorVscOnDeviceAdd ;
storDriver - > Base . OnDeviceRemove = StorVscOnDeviceRemove ;
storDriver - > Base . OnCleanup = StorVscOnCleanup ;
storDriver - > OnIORequest = StorVscOnIORequest ;
storDriver - > OnHostReset = StorVscOnHostReset ;
DPRINT_EXIT ( STORVSC ) ;
return ret ;
}
/*++
Name :
StorVscOnDeviceAdd ( )
Description :
Callback when the device belonging to this driver is added
- - */
2009-07-29 16:04:51 +00:00
static int
2009-07-13 23:01:31 +00:00
StorVscOnDeviceAdd (
2009-07-28 15:32:53 +00:00
struct hv_device * Device ,
2009-07-13 23:01:31 +00:00
void * AdditionalInfo
)
{
int ret = 0 ;
STORVSC_DEVICE * storDevice ;
2009-07-27 20:47:24 +00:00
/* VMSTORAGE_CHANNEL_PROPERTIES *props; */
2009-07-13 23:01:31 +00:00
STORVSC_DEVICE_INFO * deviceInfo = ( STORVSC_DEVICE_INFO * ) AdditionalInfo ;
DPRINT_ENTER ( STORVSC ) ;
storDevice = AllocStorDevice ( Device ) ;
if ( ! storDevice )
{
ret = - 1 ;
goto Cleanup ;
}
2009-07-27 20:47:24 +00:00
/* Save the channel properties to our storvsc channel */
/* props = (VMSTORAGE_CHANNEL_PROPERTIES*) channel->offerMsg.Offer.u.Standard.UserDefined; */
/* FIXME: */
/*
* If we support more than 1 scsi channel , we need to set the
* port number here to the scsi channel but how do we get the
* scsi channel prior to the bus scan
*/
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
/* storChannel->PortNumber = 0;
2009-07-13 23:01:31 +00:00
storChannel - > PathId = props - > PathId ;
2009-07-27 20:47:24 +00:00
storChannel - > TargetId = props - > TargetId ; */
2009-07-13 23:01:31 +00:00
storDevice - > PortNumber = deviceInfo - > PortNumber ;
2009-07-27 20:47:24 +00:00
/* Send it back up */
2009-07-13 23:01:31 +00:00
ret = StorVscConnectToVsp ( Device ) ;
2009-07-27 20:47:24 +00:00
/* deviceInfo->PortNumber = storDevice->PortNumber; */
2009-07-13 23:01:31 +00:00
deviceInfo - > PathId = storDevice - > PathId ;
deviceInfo - > TargetId = storDevice - > TargetId ;
2009-07-27 20:47:25 +00:00
DPRINT_DBG ( STORVSC , " assigned port %u, path %u target %u \n " , storDevice - > PortNumber , storDevice - > PathId , storDevice - > TargetId ) ;
2009-07-13 23:01:31 +00:00
Cleanup :
DPRINT_EXIT ( STORVSC ) ;
return ret ;
}
2009-07-28 15:32:53 +00:00
static int StorVscChannelInit ( struct hv_device * Device )
2009-07-13 23:01:31 +00:00
{
int ret = 0 ;
STORVSC_DEVICE * storDevice ;
STORVSC_REQUEST_EXTENSION * request ;
VSTOR_PACKET * vstorPacket ;
storDevice = GetStorDevice ( Device ) ;
if ( ! storDevice )
{
DPRINT_ERR ( STORVSC , " unable to get stor device...device being destroyed? " ) ;
DPRINT_EXIT ( STORVSC ) ;
return - 1 ;
}
request = & storDevice - > InitRequest ;
vstorPacket = & request - > VStorPacket ;
2009-07-27 20:47:24 +00:00
/* Now, initiate the vsc/vsp initialization protocol on the open channel */
2009-07-13 23:01:31 +00:00
memset ( request , sizeof ( STORVSC_REQUEST_EXTENSION ) , 0 ) ;
request - > WaitEvent = WaitEventCreate ( ) ;
vstorPacket - > Operation = VStorOperationBeginInitialization ;
vstorPacket - > Flags = REQUEST_COMPLETION_FLAG ;
/*SpinlockAcquire(gDriverExt.packetListLock);
INSERT_TAIL_LIST ( & gDriverExt . packetList , & packet - > listEntry . entry ) ;
SpinlockRelease ( gDriverExt . packetListLock ) ; */
DPRINT_INFO ( STORVSC , " BEGIN_INITIALIZATION_OPERATION... " ) ;
ret = Device - > Driver - > VmbusChannelInterface . SendPacket ( Device ,
vstorPacket ,
sizeof ( VSTOR_PACKET ) ,
2009-07-14 22:12:46 +00:00
( unsigned long ) request ,
2009-07-13 23:01:31 +00:00
VmbusPacketTypeDataInBand ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
if ( ret ! = 0 )
{
DPRINT_ERR ( STORVSC , " unable to send BEGIN_INITIALIZATION_OPERATION " ) ;
goto Cleanup ;
}
WaitEventWait ( request - > WaitEvent ) ;
if ( vstorPacket - > Operation ! = VStorOperationCompleteIo | | vstorPacket - > Status ! = 0 )
{
2009-07-27 20:47:25 +00:00
DPRINT_ERR ( STORVSC , " BEGIN_INITIALIZATION_OPERATION failed (op %d status 0x%x) " , vstorPacket - > Operation , vstorPacket - > Status ) ;
2009-07-13 23:01:31 +00:00
goto Cleanup ;
}
DPRINT_INFO ( STORVSC , " QUERY_PROTOCOL_VERSION_OPERATION... " ) ;
2009-07-27 20:47:24 +00:00
/* reuse the packet for version range supported */
2009-07-13 23:01:31 +00:00
memset ( vstorPacket , sizeof ( VSTOR_PACKET ) , 0 ) ;
vstorPacket - > Operation = VStorOperationQueryProtocolVersion ;
vstorPacket - > Flags = REQUEST_COMPLETION_FLAG ;
vstorPacket - > Version . MajorMinor = VMSTOR_PROTOCOL_VERSION_CURRENT ;
FILL_VMSTOR_REVISION ( vstorPacket - > Version . Revision ) ;
ret = Device - > Driver - > VmbusChannelInterface . SendPacket ( Device ,
vstorPacket ,
sizeof ( VSTOR_PACKET ) ,
2009-07-14 22:12:46 +00:00
( unsigned long ) request ,
2009-07-13 23:01:31 +00:00
VmbusPacketTypeDataInBand ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
if ( ret ! = 0 )
{
DPRINT_ERR ( STORVSC , " unable to send BEGIN_INITIALIZATION_OPERATION " ) ;
goto Cleanup ;
}
WaitEventWait ( request - > WaitEvent ) ;
2009-07-27 20:47:24 +00:00
/* TODO: Check returned version */
2009-07-13 23:01:31 +00:00
if ( vstorPacket - > Operation ! = VStorOperationCompleteIo | | vstorPacket - > Status ! = 0 )
{
2009-07-27 20:47:25 +00:00
DPRINT_ERR ( STORVSC , " QUERY_PROTOCOL_VERSION_OPERATION failed (op %d status 0x%x) " , vstorPacket - > Operation , vstorPacket - > Status ) ;
2009-07-13 23:01:31 +00:00
goto Cleanup ;
}
2009-07-27 20:47:24 +00:00
/* Query channel properties */
2009-07-13 23:01:31 +00:00
DPRINT_INFO ( STORVSC , " QUERY_PROPERTIES_OPERATION... " ) ;
memset ( vstorPacket , sizeof ( VSTOR_PACKET ) , 0 ) ;
vstorPacket - > Operation = VStorOperationQueryProperties ;
vstorPacket - > Flags = REQUEST_COMPLETION_FLAG ;
vstorPacket - > StorageChannelProperties . PortNumber = storDevice - > PortNumber ;
ret = Device - > Driver - > VmbusChannelInterface . SendPacket ( Device ,
vstorPacket ,
sizeof ( VSTOR_PACKET ) ,
2009-07-14 22:12:46 +00:00
( unsigned long ) request ,
2009-07-13 23:01:31 +00:00
VmbusPacketTypeDataInBand ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
if ( ret ! = 0 )
{
DPRINT_ERR ( STORVSC , " unable to send QUERY_PROPERTIES_OPERATION " ) ;
goto Cleanup ;
}
WaitEventWait ( request - > WaitEvent ) ;
2009-07-27 20:47:24 +00:00
/* TODO: Check returned version */
2009-07-13 23:01:31 +00:00
if ( vstorPacket - > Operation ! = VStorOperationCompleteIo | | vstorPacket - > Status ! = 0 )
{
2009-07-27 20:47:25 +00:00
DPRINT_ERR ( STORVSC , " QUERY_PROPERTIES_OPERATION failed (op %d status 0x%x) " , vstorPacket - > Operation , vstorPacket - > Status ) ;
2009-07-13 23:01:31 +00:00
goto Cleanup ;
}
2009-07-27 20:47:24 +00:00
/* storDevice->PortNumber = vstorPacket->StorageChannelProperties.PortNumber; */
2009-07-13 23:01:31 +00:00
storDevice - > PathId = vstorPacket - > StorageChannelProperties . PathId ;
storDevice - > TargetId = vstorPacket - > StorageChannelProperties . TargetId ;
2009-07-27 20:47:25 +00:00
DPRINT_DBG ( STORVSC , " channel flag 0x%x, max xfer len 0x%x " , vstorPacket - > StorageChannelProperties . Flags , vstorPacket - > StorageChannelProperties . MaxTransferBytes ) ;
2009-07-13 23:01:31 +00:00
DPRINT_INFO ( STORVSC , " END_INITIALIZATION_OPERATION... " ) ;
memset ( vstorPacket , sizeof ( VSTOR_PACKET ) , 0 ) ;
vstorPacket - > Operation = VStorOperationEndInitialization ;
vstorPacket - > Flags = REQUEST_COMPLETION_FLAG ;
ret = Device - > Driver - > VmbusChannelInterface . SendPacket ( Device ,
vstorPacket ,
sizeof ( VSTOR_PACKET ) ,
2009-07-14 22:12:46 +00:00
( unsigned long ) request ,
2009-07-13 23:01:31 +00:00
VmbusPacketTypeDataInBand ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
if ( ret ! = 0 )
{
DPRINT_ERR ( STORVSC , " unable to send END_INITIALIZATION_OPERATION " ) ;
goto Cleanup ;
}
WaitEventWait ( request - > WaitEvent ) ;
if ( vstorPacket - > Operation ! = VStorOperationCompleteIo | | vstorPacket - > Status ! = 0 )
{
2009-07-27 20:47:25 +00:00
DPRINT_ERR ( STORVSC , " END_INITIALIZATION_OPERATION failed (op %d status 0x%x) " , vstorPacket - > Operation , vstorPacket - > Status ) ;
2009-07-13 23:01:31 +00:00
goto Cleanup ;
}
DPRINT_INFO ( STORVSC , " **** storage channel up and running!! **** " ) ;
Cleanup :
if ( request - > WaitEvent )
{
2009-07-29 21:00:10 +00:00
kfree ( request - > WaitEvent ) ;
2009-07-13 23:01:31 +00:00
request - > WaitEvent = NULL ;
}
PutStorDevice ( Device ) ;
DPRINT_EXIT ( STORVSC ) ;
return ret ;
}
2009-07-29 16:04:51 +00:00
static int
2009-07-13 23:01:31 +00:00
StorVscConnectToVsp (
2009-07-28 15:32:53 +00:00
struct hv_device * Device
2009-07-13 23:01:31 +00:00
)
{
int ret = 0 ;
VMSTORAGE_CHANNEL_PROPERTIES props ;
STORVSC_DRIVER_OBJECT * storDriver = ( STORVSC_DRIVER_OBJECT * ) Device - > Driver ; ;
memset ( & props , sizeof ( VMSTORAGE_CHANNEL_PROPERTIES ) , 0 ) ;
2009-07-27 20:47:24 +00:00
/* Open the channel */
2009-07-13 23:01:31 +00:00
ret = Device - > Driver - > VmbusChannelInterface . Open ( Device ,
storDriver - > RingBufferSize ,
storDriver - > RingBufferSize ,
2009-07-14 22:06:28 +00:00
( void * ) & props ,
2009-07-13 23:01:31 +00:00
sizeof ( VMSTORAGE_CHANNEL_PROPERTIES ) ,
StorVscOnChannelCallback ,
Device
) ;
2009-07-27 20:47:25 +00:00
DPRINT_DBG ( STORVSC , " storage props: path id %d, tgt id %d, max xfer %d " , props . PathId , props . TargetId , props . MaxTransferBytes ) ;
2009-07-13 23:01:31 +00:00
if ( ret ! = 0 )
{
DPRINT_ERR ( STORVSC , " unable to open channel: %d " , ret ) ;
return - 1 ;
}
ret = StorVscChannelInit ( Device ) ;
return ret ;
}
/*++
Name :
StorVscOnDeviceRemove ( )
Description :
Callback when the our device is being removed
- - */
2009-07-29 16:04:51 +00:00
static int
2009-07-13 23:01:31 +00:00
StorVscOnDeviceRemove (
2009-07-28 15:32:53 +00:00
struct hv_device * Device
2009-07-13 23:01:31 +00:00
)
{
STORVSC_DEVICE * storDevice ;
int ret = 0 ;
DPRINT_ENTER ( STORVSC ) ;
DPRINT_INFO ( STORVSC , " disabling storage device (%p)... " , Device - > Extension ) ;
storDevice = ReleaseStorDevice ( Device ) ;
2009-07-27 20:47:24 +00:00
/*
* At this point , all outbound traffic should be disable . We
* only allow inbound traffic ( responses ) to proceed so that
* outstanding requests can be completed .
*/
2009-07-13 23:01:31 +00:00
while ( storDevice - > NumOutstandingRequests )
{
DPRINT_INFO ( STORVSC , " waiting for %d requests to complete... " , storDevice - > NumOutstandingRequests ) ;
2009-07-16 18:50:41 +00:00
udelay ( 100 ) ;
2009-07-13 23:01:31 +00:00
}
DPRINT_INFO ( STORVSC , " removing storage device (%p)... " , Device - > Extension ) ;
storDevice = FinalReleaseStorDevice ( Device ) ;
DPRINT_INFO ( STORVSC , " storage device (%p) safe to remove " , storDevice ) ;
2009-07-27 20:47:24 +00:00
/* Close the channel */
2009-07-13 23:01:31 +00:00
Device - > Driver - > VmbusChannelInterface . Close ( Device ) ;
FreeStorDevice ( storDevice ) ;
DPRINT_EXIT ( STORVSC ) ;
return ret ;
}
2009-07-27 20:47:24 +00:00
/* ***************
static void
StorVscOnTargetRescan (
void * Context
)
{
2009-07-28 15:32:53 +00:00
struct hv_device * device = ( struct hv_device * ) Context ;
2009-07-27 20:47:24 +00:00
STORVSC_DRIVER_OBJECT * storDriver ;
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
DPRINT_ENTER ( STORVSC ) ;
storDriver = ( STORVSC_DRIVER_OBJECT * ) device - > Driver ;
storDriver - > OnHostRescan ( device ) ;
DPRINT_EXIT ( STORVSC ) ;
}
* * * * * * * * * * * */
2009-07-13 23:01:31 +00:00
2009-07-29 16:04:51 +00:00
static int
2009-07-13 23:01:31 +00:00
StorVscOnHostReset (
2009-07-28 15:32:53 +00:00
struct hv_device * Device
2009-07-13 23:01:31 +00:00
)
{
int ret = 0 ;
STORVSC_DEVICE * storDevice ;
STORVSC_REQUEST_EXTENSION * request ;
VSTOR_PACKET * vstorPacket ;
DPRINT_ENTER ( STORVSC ) ;
DPRINT_INFO ( STORVSC , " resetting host adapter... " ) ;
storDevice = GetStorDevice ( Device ) ;
if ( ! storDevice )
{
DPRINT_ERR ( STORVSC , " unable to get stor device...device being destroyed? " ) ;
DPRINT_EXIT ( STORVSC ) ;
return - 1 ;
}
request = & storDevice - > ResetRequest ;
vstorPacket = & request - > VStorPacket ;
request - > WaitEvent = WaitEventCreate ( ) ;
vstorPacket - > Operation = VStorOperationResetBus ;
vstorPacket - > Flags = REQUEST_COMPLETION_FLAG ;
vstorPacket - > VmSrb . PathId = storDevice - > PathId ;
ret = Device - > Driver - > VmbusChannelInterface . SendPacket ( Device ,
vstorPacket ,
sizeof ( VSTOR_PACKET ) ,
2009-07-14 22:12:46 +00:00
( unsigned long ) & storDevice - > ResetRequest ,
2009-07-13 23:01:31 +00:00
VmbusPacketTypeDataInBand ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
if ( ret ! = 0 )
{
DPRINT_ERR ( STORVSC , " Unable to send reset packet %p ret %d " , vstorPacket , ret ) ;
goto Cleanup ;
}
2009-07-27 20:47:24 +00:00
/* FIXME: Add a timeout */
2009-07-13 23:01:31 +00:00
WaitEventWait ( request - > WaitEvent ) ;
2009-07-29 21:00:10 +00:00
kfree ( request - > WaitEvent ) ;
2009-07-13 23:01:31 +00:00
DPRINT_INFO ( STORVSC , " host adapter reset completed " ) ;
2009-07-27 20:47:24 +00:00
/*
* At this point , all outstanding requests in the adapter
* should have been flushed out and return to us
*/
2009-07-13 23:01:31 +00:00
Cleanup :
PutStorDevice ( Device ) ;
DPRINT_EXIT ( STORVSC ) ;
return ret ;
}
/*++
Name :
StorVscOnIORequest ( )
Description :
Callback to initiate an I / O request
- - */
2009-07-29 16:04:51 +00:00
static int
2009-07-13 23:01:31 +00:00
StorVscOnIORequest (
2009-07-28 15:32:53 +00:00
struct hv_device * Device ,
2009-07-29 12:10:19 +00:00
struct hv_storvsc_request * Request
2009-07-13 23:01:31 +00:00
)
{
STORVSC_DEVICE * storDevice ;
STORVSC_REQUEST_EXTENSION * requestExtension = ( STORVSC_REQUEST_EXTENSION * ) Request - > Extension ;
VSTOR_PACKET * vstorPacket = & requestExtension - > VStorPacket ;
int ret = 0 ;
DPRINT_ENTER ( STORVSC ) ;
storDevice = GetStorDevice ( Device ) ;
DPRINT_DBG ( STORVSC , " enter - Device %p, DeviceExt %p, Request %p, Extension %p " ,
Device , storDevice , Request , requestExtension ) ;
DPRINT_DBG ( STORVSC , " req %p len %d bus %d, target %d, lun %d cdblen %d " ,
Request , Request - > DataBuffer . Length , Request - > Bus , Request - > TargetId , Request - > LunId , Request - > CdbLen ) ;
if ( ! storDevice )
{
DPRINT_ERR ( STORVSC , " unable to get stor device...device being destroyed? " ) ;
DPRINT_EXIT ( STORVSC ) ;
return - 2 ;
}
2009-07-16 19:35:37 +00:00
/* print_hex_dump_bytes("", DUMP_PREFIX_NONE, Request->Cdb, Request->CdbLen); */
2009-07-13 23:01:31 +00:00
requestExtension - > Request = Request ;
requestExtension - > Device = Device ;
memset ( vstorPacket , 0 , sizeof ( VSTOR_PACKET ) ) ;
vstorPacket - > Flags | = REQUEST_COMPLETION_FLAG ;
vstorPacket - > VmSrb . Length = sizeof ( VMSCSI_REQUEST ) ;
vstorPacket - > VmSrb . PortNumber = Request - > Host ;
vstorPacket - > VmSrb . PathId = Request - > Bus ;
vstorPacket - > VmSrb . TargetId = Request - > TargetId ;
vstorPacket - > VmSrb . Lun = Request - > LunId ;
vstorPacket - > VmSrb . SenseInfoLength = SENSE_BUFFER_SIZE ;
2009-07-27 20:47:24 +00:00
/* Copy over the scsi command descriptor block */
2009-07-13 23:01:31 +00:00
vstorPacket - > VmSrb . CdbLength = Request - > CdbLen ;
memcpy ( & vstorPacket - > VmSrb . Cdb , Request - > Cdb , Request - > CdbLen ) ;
vstorPacket - > VmSrb . DataIn = Request - > Type ;
vstorPacket - > VmSrb . DataTransferLength = Request - > DataBuffer . Length ;
vstorPacket - > Operation = VStorOperationExecuteSRB ;
DPRINT_DBG ( STORVSC , " srb - len %d port %d, path %d, target %d, lun %d senselen %d cdblen %d " ,
vstorPacket - > VmSrb . Length ,
vstorPacket - > VmSrb . PortNumber ,
vstorPacket - > VmSrb . PathId ,
vstorPacket - > VmSrb . TargetId ,
vstorPacket - > VmSrb . Lun ,
vstorPacket - > VmSrb . SenseInfoLength ,
vstorPacket - > VmSrb . CdbLength ) ;
if ( requestExtension - > Request - > DataBuffer . Length )
{
ret = Device - > Driver - > VmbusChannelInterface . SendPacketMultiPageBuffer ( Device ,
& requestExtension - > Request - > DataBuffer ,
vstorPacket ,
sizeof ( VSTOR_PACKET ) ,
2009-07-14 22:12:46 +00:00
( unsigned long ) requestExtension ) ;
2009-07-13 23:01:31 +00:00
}
else
{
ret = Device - > Driver - > VmbusChannelInterface . SendPacket ( Device ,
vstorPacket ,
sizeof ( VSTOR_PACKET ) ,
2009-07-14 22:12:46 +00:00
( unsigned long ) requestExtension ,
2009-07-13 23:01:31 +00:00
VmbusPacketTypeDataInBand ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
}
if ( ret ! = 0 )
{
DPRINT_DBG ( STORVSC , " Unable to send packet %p ret %d " , vstorPacket , ret ) ;
}
InterlockedIncrement ( & storDevice - > NumOutstandingRequests ) ;
PutStorDevice ( Device ) ;
DPRINT_EXIT ( STORVSC ) ;
return ret ;
}
/*++
Name :
StorVscOnCleanup ( )
Description :
Perform any cleanup when the driver is removed
- - */
2009-07-29 16:04:51 +00:00
static void
2009-07-13 23:01:31 +00:00
StorVscOnCleanup (
2009-07-29 12:09:45 +00:00
struct hv_driver * Driver
2009-07-13 23:01:31 +00:00
)
{
DPRINT_ENTER ( STORVSC ) ;
DPRINT_EXIT ( STORVSC ) ;
}
static void
StorVscOnIOCompletion (
2009-07-28 15:32:53 +00:00
struct hv_device * Device ,
2009-07-13 23:01:31 +00:00
VSTOR_PACKET * VStorPacket ,
STORVSC_REQUEST_EXTENSION * RequestExt
)
{
2009-07-29 12:10:19 +00:00
struct hv_storvsc_request * request ;
2009-07-13 23:01:31 +00:00
STORVSC_DEVICE * storDevice ;
DPRINT_ENTER ( STORVSC ) ;
storDevice = MustGetStorDevice ( Device ) ;
if ( ! storDevice )
{
DPRINT_ERR ( STORVSC , " unable to get stor device...device being destroyed? " ) ;
DPRINT_EXIT ( STORVSC ) ;
return ;
}
2009-07-27 20:47:25 +00:00
DPRINT_DBG ( STORVSC , " IO_COMPLETE_OPERATION - request extension %p completed bytes xfer %u " ,
2009-07-13 23:01:31 +00:00
RequestExt , VStorPacket - > VmSrb . DataTransferLength ) ;
ASSERT ( RequestExt ! = NULL ) ;
ASSERT ( RequestExt - > Request ! = NULL ) ;
request = RequestExt - > Request ;
ASSERT ( request - > OnIOCompletion ! = NULL ) ;
2009-07-27 20:47:24 +00:00
/* Copy over the status...etc */
2009-07-13 23:01:31 +00:00
request - > Status = VStorPacket - > VmSrb . ScsiStatus ;
if ( request - > Status ! = 0 | | VStorPacket - > VmSrb . SrbStatus ! = 1 )
{
DPRINT_WARN ( STORVSC , " cmd 0x%x scsi status 0x%x srb status 0x%x \n " ,
request - > Cdb [ 0 ] ,
VStorPacket - > VmSrb . ScsiStatus ,
VStorPacket - > VmSrb . SrbStatus ) ;
}
2009-07-27 20:47:24 +00:00
if ( ( request - > Status & 0xFF ) = = 0x02 ) /* CHECK_CONDITION */
2009-07-13 23:01:31 +00:00
{
2009-07-27 20:47:24 +00:00
if ( VStorPacket - > VmSrb . SrbStatus & 0x80 ) /* autosense data available */
2009-07-13 23:01:31 +00:00
{
DPRINT_WARN ( STORVSC , " storvsc pkt %p autosense data valid - len %d \n " ,
RequestExt , VStorPacket - > VmSrb . SenseInfoLength ) ;
ASSERT ( VStorPacket - > VmSrb . SenseInfoLength < = request - > SenseBufferSize ) ;
memcpy ( request - > SenseBuffer ,
VStorPacket - > VmSrb . SenseData ,
VStorPacket - > VmSrb . SenseInfoLength ) ;
request - > SenseBufferSize = VStorPacket - > VmSrb . SenseInfoLength ;
}
}
2009-07-27 20:47:24 +00:00
/* TODO: */
2009-07-13 23:01:31 +00:00
request - > BytesXfer = VStorPacket - > VmSrb . DataTransferLength ;
request - > OnIOCompletion ( request ) ;
InterlockedDecrement ( & storDevice - > NumOutstandingRequests ) ;
PutStorDevice ( Device ) ;
DPRINT_EXIT ( STORVSC ) ;
}
static void
StorVscOnReceive (
2009-07-28 15:32:53 +00:00
struct hv_device * Device ,
2009-07-13 23:01:31 +00:00
VSTOR_PACKET * VStorPacket ,
STORVSC_REQUEST_EXTENSION * RequestExt
)
{
switch ( VStorPacket - > Operation )
{
case VStorOperationCompleteIo :
DPRINT_DBG ( STORVSC , " IO_COMPLETE_OPERATION " ) ;
StorVscOnIOCompletion ( Device , VStorPacket , RequestExt ) ;
break ;
2009-07-27 20:47:24 +00:00
/* case ENUMERATE_DEVICE_OPERATION: */
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
/* DPRINT_INFO(STORVSC, "ENUMERATE_DEVICE_OPERATION"); */
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
/* StorVscOnTargetRescan(Device); */
/* break; */
2009-07-13 23:01:31 +00:00
2009-07-27 20:47:24 +00:00
case VStorOperationRemoveDevice :
2009-07-13 23:01:31 +00:00
DPRINT_INFO ( STORVSC , " REMOVE_DEVICE_OPERATION " ) ;
2009-07-27 20:47:24 +00:00
/* TODO: */
2009-07-13 23:01:31 +00:00
break ;
default :
DPRINT_INFO ( STORVSC , " Unknown operation received - %d " , VStorPacket - > Operation ) ;
break ;
}
}
2009-07-29 16:04:51 +00:00
static void
2009-07-13 23:01:31 +00:00
StorVscOnChannelCallback (
2009-07-14 22:06:28 +00:00
void * Context
2009-07-13 23:01:31 +00:00
)
{
int ret = 0 ;
2009-07-28 15:32:53 +00:00
struct hv_device * device = ( struct hv_device * ) Context ;
2009-07-13 23:01:31 +00:00
STORVSC_DEVICE * storDevice ;
2009-07-14 22:09:36 +00:00
u32 bytesRecvd ;
2009-07-14 22:10:26 +00:00
u64 requestId ;
unsigned char packet [ ALIGN_UP ( sizeof ( VSTOR_PACKET ) , 8 ) ] ;
2009-07-13 23:01:31 +00:00
STORVSC_REQUEST_EXTENSION * request ;
DPRINT_ENTER ( STORVSC ) ;
ASSERT ( device ) ;
storDevice = MustGetStorDevice ( device ) ;
if ( ! storDevice )
{
DPRINT_ERR ( STORVSC , " unable to get stor device...device being destroyed? " ) ;
DPRINT_EXIT ( STORVSC ) ;
return ;
}
do
{
ret = device - > Driver - > VmbusChannelInterface . RecvPacket ( device ,
packet ,
ALIGN_UP ( sizeof ( VSTOR_PACKET ) , 8 ) ,
& bytesRecvd ,
& requestId ) ;
if ( ret = = 0 & & bytesRecvd > 0 )
{
DPRINT_DBG ( STORVSC , " receive %d bytes - tid %llx " , bytesRecvd , requestId ) ;
2009-07-27 20:47:24 +00:00
/* ASSERT(bytesRecvd == sizeof(VSTOR_PACKET)); */
2009-07-13 23:01:31 +00:00
2009-07-14 22:12:46 +00:00
request = ( STORVSC_REQUEST_EXTENSION * ) ( unsigned long ) requestId ;
2009-07-13 23:01:31 +00:00
ASSERT ( request ) ;
2009-07-27 20:47:24 +00:00
/* if (vstorPacket.Flags & SYNTHETIC_FLAG) */
2009-07-13 23:01:31 +00:00
if ( ( request = = & storDevice - > InitRequest ) | | ( request = = & storDevice - > ResetRequest ) )
{
2009-07-27 20:47:24 +00:00
/* DPRINT_INFO(STORVSC, "reset completion - operation %u status %u", vstorPacket.Operation, vstorPacket.Status); */
2009-07-13 23:01:31 +00:00
memcpy ( & request - > VStorPacket , packet , sizeof ( VSTOR_PACKET ) ) ;
WaitEventSet ( request - > WaitEvent ) ;
}
else
{
StorVscOnReceive ( device , ( VSTOR_PACKET * ) packet , request ) ;
}
}
else
{
2009-07-27 20:47:24 +00:00
/* DPRINT_DBG(STORVSC, "nothing else to read..."); */
2009-07-13 23:01:31 +00:00
break ;
}
} while ( 1 ) ;
PutStorDevice ( device ) ;
DPRINT_EXIT ( STORVSC ) ;
return ;
}