static int dc_is_this_ssd(dev_hook *hook)
{
	STORAGE_PROPERTY_QUERY         query = { StorageDeviceSeekPenaltyProperty,  PropertyStandardQuery };
	DEVICE_SEEK_PENALTY_DESCRIPTOR seek  = {0};
	char                           buff[sizeof(ATA_PASS_THROUGH_EX) + sizeof(IDENTIFY_DEVICE_DATA)] = {0};
    PATA_PASS_THROUGH_EX           pata = pv(buff);
	PIDENTIFY_DEVICE_DATA          idat = pv(buff + sizeof(ATA_PASS_THROUGH_EX));
	int                            resl;

	resl = io_hook_ioctl(hook, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &seek, sizeof(seek));

	if ( (resl == ST_OK) && (seek.Version >= sizeof(seek)) && (seek.Size >= sizeof(seek)) ) {
		DbgMsg("seek.IncursSeekPenalty %d\n", seek.IncursSeekPenalty);
		return seek.IncursSeekPenalty == FALSE;
	}
	pata->Length             = sizeof(ATA_PASS_THROUGH_EX);
	pata->DataBufferOffset   = sizeof(ATA_PASS_THROUGH_EX);
	pata->DataTransferLength = sizeof(IDENTIFY_DEVICE_DATA);
	pata->AtaFlags           = ATA_FLAGS_DATA_IN;
	pata->TimeOutValue       = 2;
	pata->CurrentTaskFile[6] = IDE_COMMAND_IDENTIFY;

	if (io_hook_ioctl(hook, IOCTL_ATA_PASS_THROUGH, buff, sizeof(buff), buff, sizeof(buff)) != ST_OK) {
		return 0;
	} else {
		DbgMsg("idat->NominalMediaRotationRate %d\n", idat->NominalMediaRotationRate);
	}
	return idat->NominalMediaRotationRate == 1;
}
int dc_fill_disk_info(dev_hook *hook)
{
	PARTITION_INFORMATION    pti;
	PARTITION_INFORMATION_EX ptix;
	DISK_GEOMETRY_EX         dgx;
	DISK_GEOMETRY            dg;
	u64                      d_size;

	if (hook->pnp_state != Started) {
		return ST_RW_ERR;
	}
	if (hook->flags & F_CDROM)
	{
		if (io_hook_ioctl(hook, IOCTL_CDROM_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg)) != ST_OK) {
			return ST_RW_ERR;
		}
		if (io_hook_ioctl(hook, IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX, NULL, 0, &dgx, sizeof(dgx)) == ST_OK) {
			d_size = dgx.DiskSize.QuadPart;
		} else {
			d_size = d64(dg.Cylinders.QuadPart) * d64(dg.TracksPerCylinder) * 
				     d64(dg.SectorsPerTrack) * d64(dg.BytesPerSector);
		}
	} else
	{
		if (io_hook_ioctl(hook, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg)) != ST_OK) {
			return ST_RW_ERR;
		}
		if (io_hook_ioctl(hook, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &ptix, sizeof(ptix)) != ST_OK)
		{
			if (io_hook_ioctl(hook, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &pti, sizeof(pti)) != ST_OK) {
				return ST_RW_ERR;
			}
			d_size = pti.PartitionLength.QuadPart;
		} else {
			d_size = ptix.PartitionLength.QuadPart;
		}
	}
	if ( (hook->flags & F_REMOVABLE) && (dc_verify_device(hook) == ST_NO_MEDIA) ) {
		return ST_NO_MEDIA;
	}
	hook->dsk_size   = d_size;
	hook->bps        = dg.BytesPerSector;
	hook->chg_last_v = hook->chg_count;
	hook->max_chunk  = dc_get_device_mtl(hook);
	hook->head_len   = max(sizeof(dc_header), hook->bps);

	if ( (hook->flags & (F_REMOVABLE | F_CDROM)) == 0 ) {
		if (dc_is_this_ssd(hook) != 0) hook->flags |= F_SSD;
	}	
	return ST_OK;
}
void dc_update_volume(dev_hook *hook)
{
	void *p_buff = NULL;
	u64   old_sz = hook->dsk_size;

	wait_object_infinity(&hook->busy_lock);

	if (IS_STORAGE_ON_END(hook->flags) != 0)
	{
		if ( (p_buff = mm_alloc(hook->head_len, 0)) == NULL ) {
			goto exit;
		}
		if (NT_SUCCESS(io_device_rw(hook->hook_dev, p_buff, hook->head_len, 0, 1)) == FALSE) {
			goto exit;
		}
	}
	if (io_hook_ioctl(hook, IOCTL_VOLUME_UPDATE_PROPERTIES, NULL, 0, NULL, 0) != ST_OK) {
		goto exit;
	}	
	if ( (dc_fill_disk_info(hook) != ST_OK) || (hook->dsk_size == old_sz) ) {
		goto exit;
	} else {
		hook->use_size += hook->dsk_size - old_sz;
	}
	if (p_buff != NULL) {
		hook->stor_off = hook->dsk_size - hook->head_len;
		io_device_rw(hook->hook_dev, p_buff, hook->head_len, 0, 0);
	}
exit:
	if (p_buff != NULL) mm_free(p_buff);
	KeReleaseMutex(&hook->busy_lock, FALSE);
}
static u32 dc_get_device_mtl(dev_hook *hook)
{
	STORAGE_ADAPTER_DESCRIPTOR sd;
	STORAGE_PROPERTY_QUERY     sq;
	IO_SCSI_CAPABILITIES       sc;
	u32                        max_chunk = 0;

	sq.PropertyId = StorageAdapterProperty;
	sq.QueryType  = PropertyStandardQuery;
	
	if (io_hook_ioctl(hook, IOCTL_STORAGE_QUERY_PROPERTY, &sq, sizeof(sq), &sd, sizeof(sd)) == ST_OK) {
		max_chunk = min(sd.MaximumTransferLength, sd.MaximumPhysicalPages * PAGE_SIZE);
	}
	if (max_chunk == 0)
	{
		if (io_hook_ioctl(hook, IOCTL_SCSI_GET_CAPABILITIES, NULL, 0, &sc, sizeof(sc)) == ST_OK) {
			max_chunk = min(sc.MaximumTransferLength, sc.MaximumPhysicalPages * PAGE_SIZE);
		}
	}
	if (max_chunk < 1024) {
		max_chunk = 32768; /* safe value */
	}
	return max_chunk;
}
int dc_verify_device(dev_hook *hook)
{
	u32 chg_count;

	if (io_hook_ioctl(hook, IOCTL_DISK_CHECK_VERIFY, NULL, 0, &chg_count, sizeof(chg_count)) == ST_OK)
	{
		if (lock_xchg(&hook->chg_count, chg_count) != chg_count) {
			return ST_MEDIA_CHANGED;
		} else {
			return ST_OK;
		}
	} else {
		return ST_NO_MEDIA;
	}
}
Beispiel #6
0
static NTSTATUS dc_trim_irp(dev_hook *hook, PIRP irp)
{
	PIO_STACK_LOCATION                 irp_sp = IoGetCurrentIrpStackLocation(irp);
	PDEVICE_MANAGE_DATA_SET_ATTRIBUTES p_set  = irp->AssociatedIrp.SystemBuffer;
	u32                                length = irp_sp->Parameters.DeviceIoControl.InputBufferLength;	
	u64                                offset, rnglen;
	PDEVICE_DATA_SET_RANGE             range;
	PDEVICE_MANAGE_DATA_SET_ATTRIBUTES n_set;
	u64                                off1, off2;
	u64                                len1, len2;
	u32                                i;

	if ( (length < sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES)) ||
		 (p_set->Action != DeviceDsmAction_Trim) ||
		 (length < d64(p_set->DataSetRangesOffset) + d64(p_set->DataSetRangesLength)) )
	{
		return dc_forward_irp(hook, irp);
	}
	if (dc_conf_flags & CONF_DISABLE_TRIM)
	{
		return dc_release_irp(hook, irp, STATUS_SUCCESS);
	}
	if ( (n_set = mm_pool_alloc(TRIM_BUFF_MAX(p_set))) == NULL )
	{
		return dc_release_irp(hook, irp, STATUS_INSUFFICIENT_RESOURCES);
	}
	n_set->Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES);
	n_set->Action = DeviceDsmAction_Trim;
	n_set->Flags = 0;
	n_set->ParameterBlockOffset = 0;
	n_set->ParameterBlockLength = 0;
	n_set->DataSetRangesOffset = _align(sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES), sizeof(DEVICE_DATA_SET_RANGE));
	n_set->DataSetRangesLength = 0;

	if (p_set->Flags & DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE)
	{
		if (hook->flags & F_NO_REDIRECT) {
			TRIM_ADD_RANGE(n_set, hook->head_len, hook->dsk_size - hook->head_len);
		} else {
			TRIM_ADD_RANGE(n_set, hook->head_len, LEN_BEFORE_STORAGE(hook));
			TRIM_ADD_RANGE(n_set, OFF_END_OF_STORAGE(hook), LEN_AFTER_STORAGE(hook));
		}
	} else
	{
		for (i = 0, range = addof(p_set, p_set->DataSetRangesOffset);
			 i < p_set->DataSetRangesLength / sizeof(DEVICE_DATA_SET_RANGE); i++, range++)
		{
			if ( (offset = range->StartingOffset) + (rnglen = range->LengthInBytes) > hook->use_size ) {
				continue;
			}
			if (hook->flags & F_NO_REDIRECT) {
				TRIM_ADD_RANGE(n_set, offset + hook->head_len, min(rnglen, hook->use_size - offset));
				continue;
			}
			len1 = intersect(&off1, offset, rnglen, hook->head_len, LEN_BEFORE_STORAGE(hook));
			len2 = intersect(&off2, offset, rnglen, OFF_END_OF_STORAGE(hook), LEN_AFTER_STORAGE(hook));

			TRIM_ADD_RANGE(n_set, off1, len1);
			TRIM_ADD_RANGE(n_set, off2, len2);
		}
	}
	if (n_set->DataSetRangesLength != 0) {
		io_hook_ioctl(hook, IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES, n_set, TRIM_BUFF_LENGTH(n_set), NULL, 0);
	}
	mm_pool_free(n_set);

	return dc_release_irp(hook, irp, STATUS_SUCCESS);
}