/* Filedisk PnP ID query-response routine. */ static NTSTATUS STDCALL WvFilediskPnpQueryId_( IN PDEVICE_OBJECT dev_obj, IN PIRP irp, IN WVL_SP_DISK_T disk ) { static const WCHAR * hw_ids[WvlDiskMediaTypes] = { WVL_M_WLIT L"\\FileFloppyDisk", WVL_M_WLIT L"\\FileHardDisk", WVL_M_WLIT L"\\FileOpticalDisc" }; WCHAR (*buf)[512]; NTSTATUS status; WV_SP_FILEDISK_T filedisk = CONTAINING_RECORD(disk, WV_S_FILEDISK_T, disk); BUS_QUERY_ID_TYPE query_type; /* Allocate a buffer. */ buf = wv_mallocz(sizeof *buf); if (!buf) { status = STATUS_INSUFFICIENT_RESOURCES; goto err_buf; } /* Populate the buffer with IDs. */ query_type = IoGetCurrentIrpStackLocation(irp)->Parameters.QueryId.IdType; switch (query_type) { case BusQueryDeviceID: swprintf(*buf, hw_ids[disk->Media]); break; case BusQueryInstanceID: /* "Location". */ swprintf(*buf, L"Hash_%08X", filedisk->hash); break; case BusQueryHardwareIDs: swprintf( *buf + swprintf(*buf, hw_ids[disk->Media]) + 1, WvlDiskCompatIds[disk->Media] ); break; case BusQueryCompatibleIDs: swprintf(*buf, WvlDiskCompatIds[disk->Media]); default: DBG("Unknown query type %d for %p!\n", query_type, filedisk); status = STATUS_INVALID_PARAMETER; goto err_query_type; } DBG("IRP_MN_QUERY_ID for file-backed disk %p.\n", filedisk); return WvlIrpComplete(irp, (ULONG_PTR) buf, STATUS_SUCCESS); err_query_type: wv_free(buf); err_buf: return WvlIrpComplete(irp, 0, status); }
/** * Handle a disk IRP_MJ_DEVICE_CONTROL IRP. * * @v Disk The disk to process with the IRP. * @v Irp The IRP to process with the disk. * @v Code The device control code. * @ret NTSTATUS The status of the operation. */ WVL_M_LIB NTSTATUS STDCALL WvlDiskDevCtl( IN WVL_SP_DISK_T Disk, IN PIRP Irp, IN ULONG POINTER_ALIGNMENT Code ) { switch (Code) { case IOCTL_STORAGE_QUERY_PROPERTY: return WvlDiskDevCtlStorageQueryProp_(Disk, Irp); case IOCTL_DISK_GET_DRIVE_GEOMETRY: return WvlDiskDevCtlGetGeom_(Disk, Irp); case IOCTL_SCSI_GET_ADDRESS: return WvlDiskDevCtlScsiGetAddr_(Disk, Irp); /* Some cases that pop up on Windows Server 2003. */ #if 0 case IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY: case IOCTL_MOUNTDEV_LINK_CREATED: case IOCTL_MOUNTDEV_QUERY_STABLE_GUID: case IOCTL_VOLUME_ONLINE: return WvlIrpComplete(Irp, 0, STATUS_SUCCESS); #endif } return WvlIrpComplete(Irp, 0, STATUS_INVALID_PARAMETER); }
static NTSTATUS STDCALL AoeBusDevCtlDetach_(IN PIRP irp) { PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp); UINT32 unit_num; WVL_SP_BUS_NODE walker; AOE_SP_DISK aoe_disk = NULL; unit_num = *((PUINT32) irp->AssociatedIrp.SystemBuffer); DBG("Request to detach unit: %d\n", unit_num); walker = NULL; /* For each node on the bus... */ WvlBusLock(&AoeBusMain); while (walker = WvlBusGetNextNode(&AoeBusMain, walker)) { aoe_disk = CONTAINING_RECORD(walker, AOE_S_DISK, BusNode[0]); /* If the unit number matches... */ if (WvlBusGetNodeNum(walker) == unit_num) { /* If it's not a boot-time device... */ if (aoe_disk->Boot) { DBG("Cannot detach a boot-time device.\n"); /* Signal error. */ aoe_disk = NULL; break; } } } WvlBusUnlock(&AoeBusMain); if (!aoe_disk) { DBG("Unit %d not found.\n", unit_num); return WvlIrpComplete(irp, 0, STATUS_INVALID_PARAMETER); } /* Detach the node. */ WvlBusRemoveNode(aoe_disk->BusNode); DBG("Removed unit %d.\n", unit_num); return WvlIrpComplete(irp, 0, STATUS_SUCCESS); }
/* Dummy PnP IRP handler. */ static NTSTATUS STDCALL WvDummyPnp( IN WV_SP_DEV_T dev, IN PIRP irp, IN UCHAR code ) { switch (code) { case IRP_MN_QUERY_ID: /* The WV_S_DEV_T extension points to the dummy IDs. */ return WvDummyIds(irp, dev->ext); case IRP_MN_QUERY_REMOVE_DEVICE: return WvlIrpComplete(irp, 0, STATUS_SUCCESS); case IRP_MN_REMOVE_DEVICE: /* Any error status for the removal slips away, here. */ WvBusRemoveDev(dev); return WvlIrpComplete(irp, 0, STATUS_SUCCESS); default: /* Return whatever upper drivers in the stack yielded. */ return WvlIrpComplete( irp, irp->IoStatus.Information, irp->IoStatus.Status ); } }
/** * Handle a PnP ID query with a WV_S_DUMMY_IDS object. * * @v Irp The PnP ID query IRP to handle. * @v DummyIds The object containing the IDs to respond with. * @ret NTSTATUS The status of the operation. */ static NTSTATUS STDCALL WvDummyIds( IN PIRP Irp, IN WV_SP_DUMMY_IDS DummyIds ) { PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(Irp); BUS_QUERY_ID_TYPE query_type = io_stack_loc->Parameters.QueryId.IdType; const CHAR * start; const WCHAR * ids; UINT32 len; NTSTATUS status; start = (const CHAR *) DummyIds + DummyIds->Offset; ids = (const WCHAR *) start; switch (query_type) { case BusQueryDeviceID: ids += DummyIds->DevOffset; len = DummyIds->DevLen; break; case BusQueryInstanceID: ids += DummyIds->InstanceOffset; len = DummyIds->InstanceLen; break; case BusQueryHardwareIDs: ids += DummyIds->HardwareOffset; len = DummyIds->HardwareLen; break; case BusQueryCompatibleIDs: ids += DummyIds->CompatOffset; len = DummyIds->CompatLen; break; default: return WvlIrpComplete(Irp, 0, STATUS_NOT_SUPPORTED); } /* Allocate the return buffer. */ Irp->IoStatus.Information = (ULONG_PTR) wv_palloc(len * sizeof *ids); if (Irp->IoStatus.Information == 0) { DBG("wv_palloc failed.\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto alloc_info; } /* Copy the working buffer to the return buffer. */ RtlCopyMemory( (PVOID) Irp->IoStatus.Information, ids, len * sizeof *ids ); status = STATUS_SUCCESS; /* irp->IoStatus.Information not freed. */ alloc_info: return WvlIrpComplete(Irp, Irp->IoStatus.Information, status); }
/* Handle an IRP. */ static NTSTATUS WvFilediskIrpDispatch( IN PDEVICE_OBJECT dev_obj, IN PIRP irp ) { PIO_STACK_LOCATION io_stack_loc; WV_SP_FILEDISK_T filedisk; NTSTATUS status; io_stack_loc = IoGetCurrentIrpStackLocation(irp); filedisk = dev_obj->DeviceExtension; switch (io_stack_loc->MajorFunction) { case IRP_MJ_SCSI: return WvlDiskScsi(dev_obj, irp, filedisk->disk); case IRP_MJ_PNP: status = WvlDiskPnp(dev_obj, irp, filedisk->disk); /* Note any state change. */ filedisk->Dev->OldState = filedisk->disk->OldState; filedisk->Dev->State = filedisk->disk->State; if (filedisk->Dev->State == WvlDiskStateNotStarted) { if (!filedisk->Dev->BusNode.Linked) { /* Unlinked _and_ deleted */ DBG("Deleting filedisk PDO: %p", dev_obj); IoDeleteDevice(dev_obj); } } return status; case IRP_MJ_DEVICE_CONTROL: return WvlDiskDevCtl( filedisk->disk, irp, io_stack_loc->Parameters.DeviceIoControl.IoControlCode ); case IRP_MJ_POWER: return WvlDiskPower(dev_obj, irp, filedisk->disk); case IRP_MJ_CREATE: case IRP_MJ_CLOSE: /* Always succeed with nothing to do. */ return WvlIrpComplete(irp, 0, STATUS_SUCCESS); case IRP_MJ_SYSTEM_CONTROL: return WvlDiskSysCtl(dev_obj, irp, filedisk->disk); default: DBG("Unhandled IRP_MJ_*: %d\n", io_stack_loc->MajorFunction); } return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED); }
/** * Handle a dummy IOCTL for creating a dummy PDO. * * @v Irp An IRP with an associated buffer containing * WV_S_DUMMY_IDS data. * @ret NTSTATUS The status of the operation. */ NTSTATUS STDCALL WvDummyIoctl(IN PIRP Irp) { WV_SP_DUMMY_IDS dummy_ids = Irp->AssociatedIrp.SystemBuffer; PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(Irp); if ( io_stack_loc->Parameters.DeviceIoControl.InputBufferLength < sizeof *dummy_ids ) { DBG("Dummy IDs too small in IRP %p.\n", Irp); return WvlIrpComplete(Irp, 0, STATUS_INVALID_PARAMETER); } return WvlIrpComplete(Irp, 0, WvDummyAdd_(dummy_ids, NULL)); }
static NTSTATUS STDCALL WvlDiskDevCtlScsiGetAddr_( IN WVL_SP_DISK_T disk, IN PIRP irp ) { PIO_STACK_LOCATION io_stack_loc= IoGetCurrentIrpStackLocation(irp); UINT32 copy_size; SCSI_ADDRESS scsi_address; copy_size = ( io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength < sizeof (SCSI_ADDRESS) ? io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength : sizeof (SCSI_ADDRESS) ); scsi_address.Length = sizeof (SCSI_ADDRESS); scsi_address.PortNumber = 0; scsi_address.PathId = 0; scsi_address.TargetId = WvlDiskUnitNum(disk); scsi_address.Lun = 0; RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, &scsi_address, copy_size ); return WvlIrpComplete(irp, (ULONG_PTR) copy_size, STATUS_SUCCESS); }
static NTSTATUS STDCALL WvlDiskDevCtlGetGeom_( IN WVL_SP_DISK_T disk, IN PIRP irp ) { PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp); UINT32 copy_size; DISK_GEOMETRY disk_geom; copy_size = ( io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength < sizeof (DISK_GEOMETRY) ? io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength : sizeof (DISK_GEOMETRY) ); disk_geom.MediaType = FixedMedia; disk_geom.Cylinders.QuadPart = disk->Cylinders; disk_geom.TracksPerCylinder = disk->Heads; disk_geom.SectorsPerTrack = disk->Sectors; disk_geom.BytesPerSector = disk->SectorSize; RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, &disk_geom, copy_size ); return WvlIrpComplete(irp, (ULONG_PTR) copy_size, STATUS_SUCCESS); }
NTSTATUS STDCALL WvDiskPnpQueryDevText( IN PDEVICE_OBJECT dev_obj, IN PIRP irp, IN WVL_SP_DISK_T disk ) { IN WV_SP_DEV_T dev = WvDevFromDevObj(dev_obj); WCHAR (*str)[512]; PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp); NTSTATUS status; UINT32 str_len; /* Allocate a string buffer. */ str = wv_mallocz(sizeof *str); if (str == NULL) { DBG("wv_malloc IRP_MN_QUERY_DEVICE_TEXT\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto alloc_str; } /* Determine the query type. */ switch (io_stack_loc->Parameters.QueryDeviceText.DeviceTextType) { case DeviceTextDescription: str_len = swprintf(*str, WVL_M_WLIT L" Disk") + 1; irp->IoStatus.Information = (ULONG_PTR) wv_palloc(str_len * sizeof *str); if (irp->IoStatus.Information == 0) { DBG("wv_palloc DeviceTextDescription\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto alloc_info; } RtlCopyMemory( (PWCHAR) irp->IoStatus.Information, str, str_len * sizeof *str ); status = STATUS_SUCCESS; goto alloc_info; case DeviceTextLocationInformation: if (disk->disk_ops.PnpQueryId) { io_stack_loc->MinorFunction = IRP_MN_QUERY_ID; io_stack_loc->Parameters.QueryId.IdType = BusQueryInstanceID; return disk->disk_ops.PnpQueryId(dev_obj, irp, disk); } /* Else, fall through... */ default: irp->IoStatus.Information = 0; status = STATUS_NOT_SUPPORTED; } /* irp->IoStatus.Information not freed. */ alloc_info: wv_free(str); alloc_str: return WvlIrpComplete(irp, irp->IoStatus.Information, status); }
/* Handle an IRP. */ NTSTATUS AoeBusIrpDispatch( IN PDEVICE_OBJECT dev_obj, IN PIRP irp ) { PIO_STACK_LOCATION io_stack_loc; NTSTATUS status; ULONG POINTER_ALIGNMENT code; io_stack_loc = IoGetCurrentIrpStackLocation(irp); switch (io_stack_loc->MajorFunction) { case IRP_MJ_PNP: status = WvlBusPnp(&AoeBusMain, irp); /* Did the bus detach? */ if (AoeBusMain.State == WvlBusStateDeleted) { AoeStop(); /* Delete. */ IoDeleteDevice(AoeBusMain.Fdo); /* Disassociate. */ AoeBusMain.Fdo = NULL; } return status; case IRP_MJ_DEVICE_CONTROL: code = io_stack_loc->Parameters.DeviceIoControl.IoControlCode; return AoeBusDevCtl(irp, code); case IRP_MJ_POWER: return WvlBusPower(&AoeBusMain, irp); case IRP_MJ_CREATE: case IRP_MJ_CLOSE: /* Always succeed with nothing to do. */ return WvlIrpComplete(irp, 0, STATUS_SUCCESS); case IRP_MJ_SYSTEM_CONTROL: return WvlBusSysCtl(&AoeBusMain, irp); default: ; } return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED); }
NTSTATUS STDCALL AoeBusDevCtl( IN PIRP irp, IN ULONG POINTER_ALIGNMENT code ) { switch(code) { case IOCTL_AOE_SCAN: return AoeBusDevCtlScan(irp); case IOCTL_AOE_SHOW: return AoeBusDevCtlShow(irp); case IOCTL_AOE_MOUNT: return AoeBusDevCtlMount(irp); case IOCTL_AOE_UMOUNT: return AoeBusDevCtlDetach_(irp); default: DBG("Unsupported IOCTL\n"); return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED); } }
/* Handle an IRP. */ static NTSTATUS WvDummyIrpDispatch( IN PDEVICE_OBJECT dev_obj, IN PIRP irp ) { PIO_STACK_LOCATION io_stack_loc; WV_SP_DEV_T dev; io_stack_loc = IoGetCurrentIrpStackLocation(irp); dev = WvDevFromDevObj(dev_obj); switch (io_stack_loc->MajorFunction) { case IRP_MJ_PNP: return WvDummyPnp( dev, irp, io_stack_loc->MinorFunction ); default: DBG("Unhandled IRP_MJ_*: %d\n", io_stack_loc->MajorFunction); } return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED); }
/* Filedisk I/O routine. */ static NTSTATUS STDCALL WvFilediskIo_( IN WVL_SP_DISK_T disk_ptr, IN WVL_E_DISK_IO_MODE mode, IN LONGLONG start_sector, IN UINT32 sector_count, IN PUCHAR buffer, IN PIRP irp ) { WV_SP_FILEDISK_T filedisk_ptr; LARGE_INTEGER offset; NTSTATUS status; IO_STATUS_BLOCK io_status; if (sector_count < 1) { /* A silly request. */ DBG("sector_count < 1; cancelling\n"); return WvlIrpComplete(irp, 0, STATUS_CANCELLED); } /* Establish pointer to the filedisk. */ filedisk_ptr = CONTAINING_RECORD(disk_ptr, WV_S_FILEDISK_T, disk); /* * These SCSI read/write IRPs should be completed in the thread context. * Check if the IRP was already marked pending. */ if (!(IoGetCurrentIrpStackLocation(irp)->Control & SL_PENDING_RETURNED)) { /* Enqueue and signal work. */ IoMarkIrpPending(irp); ExInterlockedInsertTailList( filedisk_ptr->Irps, &irp->Tail.Overlay.ListEntry, filedisk_ptr->IrpsLock ); KeSetEvent(&filedisk_ptr->Thread->Signal, 0, FALSE); return STATUS_PENDING; } /* Calculate the offset. */ offset.QuadPart = start_sector * disk_ptr->SectorSize; offset.QuadPart += filedisk_ptr->offset.QuadPart; /* Perform the read/write. */ if (mode == WvlDiskIoModeWrite) { status = ZwWriteFile( filedisk_ptr->file, NULL, NULL, NULL, &io_status, buffer, sector_count * disk_ptr->SectorSize, &offset, NULL ); } else { status = ZwReadFile( filedisk_ptr->file, NULL, NULL, NULL, &io_status, buffer, sector_count * disk_ptr->SectorSize, &offset, NULL ); /* When the MBR is read, re-determine the disk geometry. */ if (!start_sector) WvlDiskGuessGeometry((WVL_AP_DISK_BOOT_SECT) buffer, disk_ptr); } return WvlIrpComplete(irp, sector_count * disk_ptr->SectorSize, status); }
static NTSTATUS STDCALL AoeBusPnpQueryDevText_( IN WVL_SP_BUS_T bus, IN PIRP irp ) { WCHAR (*str)[512]; PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp); NTSTATUS status; UINT32 str_len; /* Allocate a string buffer. */ str = wv_mallocz(sizeof *str); if (str == NULL) { DBG("wv_malloc IRP_MN_QUERY_DEVICE_TEXT\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto alloc_str; } /* Determine the query type. */ switch (io_stack_loc->Parameters.QueryDeviceText.DeviceTextType) { case DeviceTextDescription: str_len = swprintf(*str, L"AoE Bus") + 1; irp->IoStatus.Information = (ULONG_PTR) wv_palloc(str_len * sizeof **str); if (irp->IoStatus.Information == 0) { DBG("wv_palloc DeviceTextDescription\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto alloc_info; } RtlCopyMemory( (PWCHAR) irp->IoStatus.Information, str, str_len * sizeof **str ); status = STATUS_SUCCESS; goto alloc_info; case DeviceTextLocationInformation: str_len = AoeBusPnpId_( NULL, BusQueryInstanceID, str ); irp->IoStatus.Information = (ULONG_PTR) wv_palloc(str_len * sizeof **str); if (irp->IoStatus.Information == 0) { DBG("wv_palloc DeviceTextLocationInformation\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto alloc_info; } RtlCopyMemory( (PWCHAR) irp->IoStatus.Information, str, str_len * sizeof **str ); status = STATUS_SUCCESS; goto alloc_info; default: irp->IoStatus.Information = 0; status = STATUS_NOT_SUPPORTED; } /* irp->IoStatus.Information not freed. */ alloc_info: wv_free(str); alloc_str: return WvlIrpComplete(irp, irp->IoStatus.Information, status); }
static NTSTATUS STDCALL WvlDiskDevCtlStorageQueryProp_( IN WVL_SP_DISK_T disk, IN PIRP irp ) { PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp); NTSTATUS status = STATUS_INVALID_PARAMETER; PSTORAGE_PROPERTY_QUERY storage_prop_query = irp->AssociatedIrp.SystemBuffer; UINT32 copy_size; STORAGE_ADAPTER_DESCRIPTOR storage_adapter_desc; STORAGE_DEVICE_DESCRIPTOR storage_dev_desc; if ( storage_prop_query->PropertyId == StorageAdapterProperty && storage_prop_query->QueryType == PropertyStandardQuery ) { copy_size = ( io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength < sizeof (STORAGE_ADAPTER_DESCRIPTOR) ? io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength : sizeof (STORAGE_ADAPTER_DESCRIPTOR) ); storage_adapter_desc.Version = sizeof (STORAGE_ADAPTER_DESCRIPTOR); storage_adapter_desc.Size = sizeof (STORAGE_ADAPTER_DESCRIPTOR); storage_adapter_desc.MaximumTransferLength = WvlDiskMaxXferLen(disk); #if 0 storage_adapter_desc.MaximumTransferLength = SECTORSIZE * POOLSIZE; #endif storage_adapter_desc.MaximumPhysicalPages = (UINT32) -1; storage_adapter_desc.AlignmentMask = 0; storage_adapter_desc.AdapterUsesPio = TRUE; storage_adapter_desc.AdapterScansDown = FALSE; storage_adapter_desc.CommandQueueing = FALSE; storage_adapter_desc.AcceleratedTransfer = FALSE; storage_adapter_desc.BusType = BusTypeScsi; RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, &storage_adapter_desc, copy_size ); status = STATUS_SUCCESS; } if ( storage_prop_query->PropertyId == StorageDeviceProperty && storage_prop_query->QueryType == PropertyStandardQuery ) { copy_size = ( io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength < sizeof (STORAGE_DEVICE_DESCRIPTOR) ? io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength : sizeof (STORAGE_DEVICE_DESCRIPTOR) ); storage_dev_desc.Version = sizeof (STORAGE_DEVICE_DESCRIPTOR); storage_dev_desc.Size = sizeof (STORAGE_DEVICE_DESCRIPTOR); storage_dev_desc.DeviceType = DIRECT_ACCESS_DEVICE; storage_dev_desc.DeviceTypeModifier = 0; storage_dev_desc.RemovableMedia = WvlDiskIsRemovable[disk->Media]; storage_dev_desc.CommandQueueing = FALSE; storage_dev_desc.VendorIdOffset = 0; storage_dev_desc.ProductIdOffset = 0; storage_dev_desc.ProductRevisionOffset = 0; storage_dev_desc.SerialNumberOffset = 0; storage_dev_desc.BusType = BusTypeScsi; storage_dev_desc.RawPropertiesLength = 0; RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, &storage_dev_desc, copy_size ); status = STATUS_SUCCESS; } if (status == STATUS_INVALID_PARAMETER) { DBG( "!!Invalid IOCTL_STORAGE_QUERY_PROPERTY " "(PropertyId: %08x / QueryType: %08x)!!\n", storage_prop_query->PropertyId, storage_prop_query->QueryType ); return WvlIrpComplete(irp, 0, status); } return WvlIrpComplete(irp, (ULONG_PTR) copy_size, status); }