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; } }
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); }