This gets the trim command as WRITE SAME operation to SCSI

* Neither hardware nor driver to test it; AHCI/IDE support is next
  on the table.
This commit is contained in:
Axel Dörfler
2013-11-07 19:03:35 +01:00
parent 0a0ba4b5f0
commit 960c56aea5
5 changed files with 93 additions and 13 deletions
+8 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2008, Haiku, Inc. All RightsReserved.
* Copyright 2004-2013, Haiku, Inc. All RightsReserved.
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
@@ -7,6 +7,7 @@
#ifndef _SCSI_PERIPH_H
#define _SCSI_PERIPH_H
/*! Use this module to minimize work required to write a SCSI
peripheral driver.
@@ -114,6 +115,12 @@ typedef struct scsi_periph_interface {
// request - ccb for this device; is used to talk to device
status_t (*check_capacity)(scsi_periph_device device, scsi_ccb *request);
// synchronizes (flush) the device cache
err_res (*synchronize_cache)(scsi_periph_device device, scsi_ccb *request);
status_t (*trim_device)(scsi_periph_device_info *device, scsi_ccb *request,
uint64 offset, uint64 numBlocks);
// *** removable media ***
// to be called when a medium change is detected to block subsequent commands
void (*media_changed)(scsi_periph_device device);
@@ -128,8 +135,6 @@ typedef struct scsi_periph_interface {
// returns: B_OK, B_DEV_MEDIA_CHANGE_REQUESTED, B_NO_MEMORY or
// pending error reported by handle_get_error
status_t (*get_media_status)(scsi_periph_handle handle);
// synchronizes (flush) the device cache
err_res(*synchronize_cache)(scsi_periph_device device, scsi_ccb *request);
// compose device name consisting of prefix and path/target/LUN
// (result must be freed by caller)
@@ -1,9 +1,10 @@
/*
* Copyright 2008-2012, Axel Dörfler, [email protected].
* Copyright 2008-2013, Axel Dörfler, [email protected].
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*! Peripheral driver to handle any kind of SCSI disks,
i.e. hard disk and floopy disks (ZIP etc.)
@@ -93,7 +94,6 @@ get_geometry(das_handle* handle, device_geometry* geometry)
if (status != B_OK)
return status;
devfs_compute_geometry_size(geometry, info->capacity, info->block_size);
geometry->device_type = B_DISK;
@@ -153,6 +153,24 @@ synchronize_cache(das_driver_info *device)
}
static status_t
trim_device(das_driver_info* device, off_t offset, off_t size)
{
TRACE("trim_device()\n");
scsi_ccb* request = device->scsi->alloc_ccb(device->scsi_device);
if (request == NULL)
return B_NO_MEMORY;
status_t status = sSCSIPeripheral->trim_device(device->scsi_periph_device,
request, offset / device->block_size, size / device->block_size);
device->scsi->free_ccb(request);
return status;
}
static int
log2(uint32 x)
{
@@ -385,6 +403,21 @@ das_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
case B_FLUSH_DRIVE_CACHE:
return synchronize_cache(info);
case B_TRIM_DEVICE:
{
fs_trim_data trimData;
if (user_memcpy(&trimData, buffer, sizeof(fs_trim_data)) != B_OK)
return B_BAD_ADDRESS;
status_t status = trim_device(info, trimData.offset, trimData.size);
if (status != B_OK)
return status;
trimData.trimmed_size = trimData.size;
return user_memcpy(buffer, &trimData, sizeof(fs_trim_data));
}
default:
return sSCSIPeripheral->ioctl(handle->scsi_periph_handle, op,
buffer, length);
@@ -649,7 +682,7 @@ struct driver_module_info sSCSIDiskDriver = {
das_init_driver,
das_uninit_driver,
das_register_child_devices,
das_rescan_child_devices,
das_rescan_child_devices,
NULL, // removed
};
@@ -1,12 +1,12 @@
/*
* Copyright 2004-2011, Haiku, Inc. All RightsReserved.
* Copyright 2004-2013, Haiku, Inc. All RightsReserved.
* Copyright 2002-2003, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
//! Handling of block device (currently, only a capacity check is provided)
//! Handling of block device
#include "scsi_periph_int.h"
@@ -59,10 +59,10 @@ periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *request)
if (capacity == UINT_MAX) {
mutex_unlock(&device->mutex);
scsi_cmd_read_capacity_long *cmd
= (scsi_cmd_read_capacity_long *)request->cdb;
scsi_res_read_capacity_long capacityLongResult;
request->data = (uint8*)&capacityLongResult;
request->data_length = sizeof(capacityLongResult);
@@ -114,3 +114,42 @@ periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *request)
return res;
}
status_t
periph_trim_device(scsi_periph_device_info *device, scsi_ccb *request,
uint64 offset, uint64 numBlocks)
{
err_res res;
int retries = 0;
do {
request->flags = SCSI_DIR_OUT;
request->sort = offset;
request->timeout = device->std_timeout;
scsi_cmd_wsame_16* cmd = (scsi_cmd_wsame_16*)request->cdb;
memset(cmd, 0, sizeof(*cmd));
cmd->opcode = SCSI_OP_WRITE_SAME_16;
cmd->unmap = 1;
cmd->lba = B_HOST_TO_BENDIAN_INT64(offset);
cmd->length = B_HOST_TO_BENDIAN_INT32(numBlocks);
request->cdb_length = sizeof(*cmd);
device->scsi->async_io(request);
acquire_sem(request->completion_sem);
// ask generic peripheral layer what to do now
res = periph_check_error(device, request);
} while ((res.action == err_act_retry && retries++ < 3)
|| (res.action == err_act_many_retries && retries++ < 30));
// peripheral layer only creates "read" error
if (res.error_code == B_DEV_READ_ERROR)
return B_DEV_WRITE_ERROR;
return res.error_code;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2008, Haiku, Inc. All RightsReserved.
* Copyright 2004-2013, Haiku, Inc. All RightsReserved.
* Copyright 2002-2003, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
@@ -135,12 +135,13 @@ static scsi_periph_interface sSCSIPeripheralModule = {
periph_io,
periph_ioctl,
periph_check_capacity,
periph_synchronize_cache,
periph_trim_device,
periph_media_changed_public,
periph_check_error,
periph_send_start_stop,
periph_get_media_status,
periph_synchronize_cache,
periph_compose_device_name
};
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2008, Haiku, Inc. All Rights Reserved.
* Copyright 2004-2013, Haiku, Inc. All Rights Reserved.
* Copyright 2002, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
@@ -77,6 +77,8 @@ status_t periph_handle_free(scsi_periph_handle_info *handle);
// block.c
status_t periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *ccb);
status_t periph_trim_device(scsi_periph_device_info *device, scsi_ccb *request,
uint64 offset, uint64 numBlocks);
// device.c