hrev46325 adds 19 changesets to branch 'master' old head: 34ce2cefc8c211af77d0660309323358b3c34adc new head: 0c873619ce86975e9ed3c66e88ca4dc9ef303a82 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=0c87361+%5E34ce2ce ---------------------------------------------------------------------------- 29a8450: Added B_TRIM_DEVICE ioctl. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] a352b43: Added fstrim command. Later, there should be a service that runs this from time to time for all devices that support it. Conflicts: build/jam/HaikuImage [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 0a0ba4b: Added B_TRIM_DEVICE support to BFS. * It currently ignores the offset/size, though, and always trims everything. * Now only SCSI support is missing. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 960c56a: 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. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 99086aa: trim: Target SCSI UNMAP command instead of WRITE SAME. * The UNMAP command is theoretically much faster, as it can get many block ranges instead of just a single range. * Furthermore, the ATA TRIM command resembles it much better. * Therefore, fs_trim_data now gets an array of ranges, and we use SCSI UNMAP to trim. * Updated BFS code to collect array ranges to fully support the new fs_trim_data possibilities. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 33945c5: ahci: Pushed TRIM support a tiny bit further. * Now doesn't do anything on SCSI_OP_UNMAP, instead of doing nothing on SCSI_OP_WRITE_SAME_16. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 13e72c9: ahci: Minor cleanup. * Mostly utilized ATACommands.h [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] d82e6bc: ahci: Use get_memory_map_etc(). * Simplifies code a bit. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 6317a4c: scsi_periph: fixed copy&paste error in periph_trim_device(). [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] e858a6b: ahci: WIP of implementing trim command. * Data Set Management specific bits are still missing. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 10deaef: ahci: Added missing wait_for_completion(). * Thanks Marcus! * That made the return code for ExecuteSataRequest() pretty much useless, so I removed it again. * Also, a delete sreq was missing; I now allocate it on the stack instead. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] fd88486: ahci: Set the command bits as required. * The trim command should be functional now, but it's completely untested at this point. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 930cb42: ahci: Minor cleanup. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 2e4e1eb: ahci: fixed endless loop, and missing bit. * The value for trim is bit 0, not 0; added sata_request::SetFeature() to change this. * The lba range fill loop never ended. * Thanks to Marcus for proof-reading! [ Axel Doerfler <axeld@xxxxxxxxxxxxxxxx> ] dbeb6b5: ahci: Fixed braindead variable naming. * Again, thanks Marcus! [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 79cb543: ahci: Minor coding style cleanup. * Renamed some methods to camel case. * Replaced coding error panics with ASSERTs. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 547cd46: trim: Added is_called_via_syscall() function. * And use it in get_trim_data_from_user(), formerly known as copy_*(). * This fixes differentiating between user and kernel buffers. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] e6bde50: scsi_periph: use synchronous command. * The call waited anyway, so there is no reason to make it async. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] 0c87361: ahci: Fixed missing endian conversion. * Spotted by Rene, thanks a lot! [ Axel Doerfler <axeld@xxxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- 23 files changed, 769 insertions(+), 185 deletions(-) build/jam/images/HaikuImage | 2 +- headers/os/drivers/Drivers.h | 14 +- headers/private/drivers/scsi_cmds.h | 37 ++- headers/private/drivers/scsi_periph.h | 15 +- headers/private/fs_shell/fssh_api_wrapper.h | 5 + headers/private/fs_shell/fssh_drivers.h | 24 +- headers/private/kernel/syscall_restart.h | 16 +- headers/private/kernel/util/fs_trim_support.h | 65 +++++ .../kernel/busses/scsi/ahci/ahci_port.cpp | 265 ++++++++++++------- src/add-ons/kernel/busses/scsi/ahci/ahci_port.h | 4 +- .../kernel/busses/scsi/ahci/sata_request.cpp | 60 +++-- .../kernel/busses/scsi/ahci/sata_request.h | 78 +++--- .../drivers/disk/scsi/scsi_disk/scsi_disk.cpp | 50 +++- .../kernel/file_systems/bfs/BlockAllocator.cpp | 107 +++++++- .../kernel/file_systems/bfs/BlockAllocator.h | 10 +- .../kernel/file_systems/bfs/kernel_interface.cpp | 31 ++- src/add-ons/kernel/generic/scsi_periph/Jamfile | 2 +- src/add-ons/kernel/generic/scsi_periph/block.cpp | 72 ++++- .../kernel/generic/scsi_periph/scsi_periph.cpp | 5 +- .../kernel/generic/scsi_periph/scsi_periph_int.h | 4 +- src/add-ons/kernel/network/stack/utility.cpp | 5 +- src/bin/Jamfile | 1 + src/bin/fstrim.cpp | 82 ++++++ ############################################################################ Commit: 29a845084326c35014460ab2c3cb23c89d239d38 URL: http://cgit.haiku-os.org/haiku/commit/?id=29a8450 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Sun Aug 4 21:19:43 2013 UTC Added B_TRIM_DEVICE ioctl. ---------------------------------------------------------------------------- diff --git a/headers/os/drivers/Drivers.h b/headers/os/drivers/Drivers.h index 3484dbf..ff4e1e0 100644 --- a/headers/os/drivers/Drivers.h +++ b/headers/os/drivers/Drivers.h @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011, Haiku Inc. All Rights Reserved. + * Copyright 2002-2013, Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _DRIVERS_DRIVERS_H @@ -106,6 +106,7 @@ enum { B_GET_ICON_NAME, /* get an icon name identifier */ B_GET_VECTOR_ICON, /* retrieves the device's vector icon */ B_GET_DEVICE_NAME, /* get name, string buffer */ + B_TRIM_DEVICE, /* trims blocks, see fs_trim_data */ B_GET_NEXT_OPEN_DEVICE = 1000, /* obsolete, will be removed */ B_ADD_FIXED_DRIVER, /* obsolete, will be removed */ @@ -169,6 +170,14 @@ typedef struct { } device_icon; +/* B_TRIM_DEVICE data structure */ +typedef struct { + off_t offset; /* offset (in bytes) */ + off_t size; + off_t trimmed_size; /* filled on return */ +} fs_trim_data; + + #ifdef __cplusplus } #endif diff --git a/headers/private/fs_shell/fssh_api_wrapper.h b/headers/private/fs_shell/fssh_api_wrapper.h index edb40a9..b0d9a3d 100644 --- a/headers/private/fs_shell/fssh_api_wrapper.h +++ b/headers/private/fs_shell/fssh_api_wrapper.h @@ -435,6 +435,10 @@ #define B_SET_INTERRUPTABLE_IO FSSH_B_SET_INTERRUPTABLE_IO #define B_FLUSH_DRIVE_CACHE FSSH_B_FLUSH_DRIVE_CACHE #define B_GET_PATH_FOR_DEVICE FSSH_B_GET_PATH_FOR_DEVICE +#define B_GET_ICON_NAME FSSH_B_GET_ICON_NAME +#define B_GET_VECTOR_ICON FSSH_B_GET_VECTOR_ICON +#define B_GET_DEVICE_NAME FSSH_B_GET_DEVICE_NAME +#define B_TRIM_DEVICE FSSH_B_TRIM_DEVICE #define B_GET_NEXT_OPEN_DEVICE FSSH_B_GET_NEXT_OPEN_DEVICE #define B_ADD_FIXED_DRIVER FSSH_B_ADD_FIXED_DRIVER #define B_REMOVE_FIXED_DRIVER FSSH_B_REMOVE_FIXED_DRIVER @@ -462,6 +466,7 @@ #define driver_path fssh_driver_path #define open_device_iterator fssh_open_device_iterator #define device_icon fssh_device_icon +#define fs_trim_data fssh_fs_trim_data //////////////////////////////////////////////////////////////////////////////// diff --git a/headers/private/fs_shell/fssh_drivers.h b/headers/private/fs_shell/fssh_drivers.h index a4d25bb..aa63da3 100644 --- a/headers/private/fs_shell/fssh_drivers.h +++ b/headers/private/fs_shell/fssh_drivers.h @@ -60,7 +60,7 @@ fssh_status_t fssh_init_hardware(void); const char **fssh_publish_devices(void); fssh_device_hooks *fssh_find_device(const char *name); fssh_status_t fssh_init_driver(void); -void fssh_uninit_driver(void); +void fssh_uninit_driver(void); extern int32_t fssh_api_version; @@ -111,17 +111,20 @@ enum { /* B_DEV_MEDIA_CHANGE_REQUESTED: user */ /* pressed button on drive */ /* B_DEV_DOOR_OPEN: door open */ - + FSSH_B_LOAD_MEDIA, /* load the media if supported */ - + FSSH_B_GET_BIOS_DRIVE_ID, /* get bios id for this device */ FSSH_B_SET_UNINTERRUPTABLE_IO, /* prevent cntl-C from interrupting i/o */ FSSH_B_SET_INTERRUPTABLE_IO, /* allow cntl-C to interrupt i/o */ FSSH_B_FLUSH_DRIVE_CACHE, /* flush drive cache */ - FSSH_B_GET_PATH_FOR_DEVICE, /* get the absolute path of the device */ + FSSH_B_GET_ICON_NAME, /* get an icon name identifier */ + FSSH_B_GET_VECTOR_ICON, /* retrieves the device's vector icon */ + FSSH_B_GET_DEVICE_NAME, /* get name, string buffer */ + FSSH_B_TRIM_DEVICE, /* trims blocks, see fs_trim_data */ FSSH_B_GET_NEXT_OPEN_DEVICE = 1000, /* iterate through open devices */ FSSH_B_ADD_FIXED_DRIVER, /* private */ @@ -196,7 +199,7 @@ typedef char fssh_driver_path[256]; typedef struct { uint32_t cookie; /* must be set to 0 before iterating */ - char device[256]; /* device path */ + char device[256]; /* device path */ } fssh_open_device_iterator; @@ -210,6 +213,14 @@ typedef struct { } fssh_device_icon; +/* B_TRIM_DEVICE data structure */ +typedef struct { + fssh_off_t offset; /* offset (in bytes) */ + fssh_off_t size; + fssh_off_t trimmed_size; /* filled on return */ +} fssh_fs_trim_data; + + #ifdef __cplusplus } #endif ############################################################################ Commit: a352b438960f14e070d0850080706f9930dcd30f URL: http://cgit.haiku-os.org/haiku/commit/?id=a352b43 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Sun Aug 4 22:14:52 2013 UTC Added fstrim command. Later, there should be a service that runs this from time to time for all devices that support it. Conflicts: build/jam/HaikuImage ---------------------------------------------------------------------------- diff --git a/build/jam/images/HaikuImage b/build/jam/images/HaikuImage index 3dd454f..74bfa6d 100644 --- a/build/jam/images/HaikuImage +++ b/build/jam/images/HaikuImage @@ -13,7 +13,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures diskimage draggers driveinfo dstcheck du dumpcatalog echo eject env error expand expr factor false fdinfo ffm filepanel find finddir findpaths FirstBootPrompt fmt - fold fortune frcode ftp ftpd funzip fwcontrol@x86 + fold fortune frcode fstrim ftp ftpd funzip fwcontrol@x86 gawk gdb@x86 getlimits groupadd groupdel groupmod groups gzip gzexe hd head hey hostname id ident ifconfig <bin>install installsound iroster isvolume diff --git a/src/bin/Jamfile b/src/bin/Jamfile index aeb8a76..e2fb698 100644 --- a/src/bin/Jamfile +++ b/src/bin/Jamfile @@ -35,6 +35,7 @@ StdBinCommands error.c fortune.c finddir.c + fstrim.cpp hd.c idestatus.c listarea.c diff --git a/src/bin/fstrim.cpp b/src/bin/fstrim.cpp new file mode 100644 index 0000000..d5dda26 --- /dev/null +++ b/src/bin/fstrim.cpp @@ -0,0 +1,81 @@ +/* + * Copyright 2013, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Distributed under the terms of the MIT license. + */ + + +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <Drivers.h> + +#include <AutoDeleter.h> + + +static struct option const kLongOptions[] = { + {"help", no_argument, 0, 'h'}, + {NULL} +}; + + +extern const char *__progname; +static const char *kProgramName = __progname; + + +void +usage(int returnValue) +{ + fprintf(stderr, "Usage: %s <path-to-mounted-file-system>\n", kProgramName); + exit(returnValue); +} + + +int +main(int argc, char** argv) +{ + int c; + while ((c = getopt_long(argc, argv, "h", kLongOptions, NULL)) != -1) { + switch (c) { + case 0: + break; + case 'h': + usage(0); + break; + default: + usage(1); + break; + } + } + + if (argc - optind < 1) + usage(1); + const char* path = argv[optind++]; + + int fd = open(path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: Could not access path: %s\n", kProgramName, + strerror(errno)); + return EXIT_FAILURE; + } + + FileDescriptorCloser closer(fd); + + fs_trim_data trimData; + trimData.offset = 0; + trimData.size = OFF_MAX; + trimData.trimmed_size = 0; + + if (ioctl(fd, B_TRIM_DEVICE, &trimData, sizeof(fs_trim_data)) != 0) { + fprintf(stderr, "%s: Trimming failed: %s\n", kProgramName, + strerror(errno)); + return EXIT_FAILURE; + } + + printf("Trimmed %lld bytes from device.\n", trimData.trimmed_size); + return EXIT_SUCCESS; +} ############################################################################ Commit: 0a0ba4b5f09da93410943578b6c5aa1f3aa60cb0 URL: http://cgit.haiku-os.org/haiku/commit/?id=0a0ba4b Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Sun Aug 4 22:16:54 2013 UTC Added B_TRIM_DEVICE support to BFS. * It currently ignores the offset/size, though, and always trims everything. * Now only SCSI support is missing. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp index a6aceca..432df6c 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2012, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Copyright 2001-2013, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. * This file may be used under the terms of the MIT License. */ @@ -1190,6 +1190,62 @@ BlockAllocator::_CheckGroup(int32 groupIndex) const #endif // DEBUG_ALLOCATION_GROUPS +status_t +BlockAllocator::Trim(off_t offset, off_t size, off_t& trimmedSize) +{ + RecursiveLocker locker(fLock); + + // TODO: take given offset and size into account! + int32 lastGroup = fNumGroups - 1; + uint32 firstBlock = 0; + uint32 firstBit = 0; + off_t currentBlock = 0; + uint32 blockShift = fVolume->BlockShift(); + + off_t firstFree = -1; + size_t freeLength = 0; + trimmedSize = 0; + + AllocationBlock cached(fVolume); + for (int32 groupIndex = 0; groupIndex <= lastGroup; groupIndex++) { + AllocationGroup& group = fGroups[groupIndex]; + + for (uint32 block = firstBlock; block < group.NumBlocks(); block++) { + cached.SetTo(group, block); + + for (uint32 i = firstBit; i < cached.NumBlockBits(); i++) { + if (cached.IsUsed(i)) { + // Block is in use + if (freeLength > 0) { + status_t status = _TrimNext(firstFree << blockShift, + freeLength << blockShift, trimmedSize); + if (status != B_OK) + return status; + + freeLength = 0; + } + } else if (freeLength++ == 0) { + // Block is free, start new free range + firstFree = currentBlock; + } + + currentBlock++; + } + } + + firstBlock = 0; + firstBit = 0; + } + + if (freeLength > 0) { + return _TrimNext(firstFree << blockShift, freeLength << blockShift, + trimmedSize); + } + + return B_OK; +} + + // #pragma mark - Bitmap validity checking // TODO: implement new FS checking API @@ -2124,6 +2180,26 @@ BlockAllocator::_AddInodeToIndex(Inode* inode) } +status_t +BlockAllocator::_TrimNext(off_t offset, off_t size, off_t& trimmedSize) +{ + PRINT(("_TrimNext(offset %lld, size %lld)\n", offset, size)); + + fs_trim_data trimData; + trimData.offset = offset; + trimData.size = size; + trimData.trimmed_size = 0; + + if (ioctl(fVolume->Device(), B_TRIM_DEVICE, &trimData, + sizeof(fs_trim_data)) != 0) { + return errno; + } + + trimmedSize += trimData.trimmed_size; + return B_OK; +} + + // #pragma mark - debugger commands diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h index ba490ba..88b9d52 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2012, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Copyright 2001-2013, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. * This file may be used under the terms of the MIT License. */ #ifndef BLOCK_ALLOCATOR_H @@ -46,6 +46,8 @@ public: int32 group, uint16 start, uint16 numBlocks, uint16 minimum, block_run& run); + status_t Trim(off_t offset, off_t size, off_t& trimmedSize); + status_t StartChecking(const check_control* control); status_t StopChecking(check_control* control); status_t CheckNextNode(check_control* control); @@ -81,6 +83,8 @@ private: void _FreeIndices(); status_t _AddInodeToIndex(Inode* inode); status_t _WriteBackCheckBitmap(); + status_t _TrimNext(off_t offset, off_t size, + off_t& trimmedSize); static status_t _Initialize(BlockAllocator* self); diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index 6504c99..1140003 100644 --- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Copyright 2001-2013, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. * This file may be used under the terms of the MIT License. */ @@ -623,6 +623,20 @@ bfs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd, Volume* volume = (Volume*)_volume->private_volume; switch (cmd) { + 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 = volume->Allocator().Trim(trimData.offset, + trimData.size, trimData.trimmed_size); + if (status != B_OK) + return status; + + return user_memcpy(buffer, &trimData, sizeof(fs_trim_data)); + } + case BFS_IOCTL_VERSION: { uint32 version = 0x10000; ############################################################################ Commit: 960c56aea53d8a930ab5dbbd3265e2b14e04e0ae URL: http://cgit.haiku-os.org/haiku/commit/?id=960c56a Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Sun Aug 4 22:51:37 2013 UTC 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. ---------------------------------------------------------------------------- diff --git a/headers/private/drivers/scsi_periph.h b/headers/private/drivers/scsi_periph.h index 03fd57e..b879521 100644 --- a/headers/private/drivers/scsi_periph.h +++ b/headers/private/drivers/scsi_periph.h @@ -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) diff --git a/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp b/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp index d3d13af..c566396 100644 --- a/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2008-2012, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Copyright 2008-2013, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. * 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 }; diff --git a/src/add-ons/kernel/generic/scsi_periph/block.cpp b/src/add-ons/kernel/generic/scsi_periph/block.cpp index 3b3ac63..0c6eb0d 100644 --- a/src/add-ons/kernel/generic/scsi_periph/block.cpp +++ b/src/add-ons/kernel/generic/scsi_periph/block.cpp @@ -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; +} + diff --git a/src/add-ons/kernel/generic/scsi_periph/scsi_periph.cpp b/src/add-ons/kernel/generic/scsi_periph/scsi_periph.cpp index c3b1663..7970698 100644 --- a/src/add-ons/kernel/generic/scsi_periph/scsi_periph.cpp +++ b/src/add-ons/kernel/generic/scsi_periph/scsi_periph.cpp @@ -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 }; diff --git a/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h b/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h index c7493a5..30df67a 100644 --- a/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h +++ b/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h @@ -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 ############################################################################ Commit: 99086aa32333be5792b0f059ccbbe3c90be05ea6 URL: http://cgit.haiku-os.org/haiku/commit/?id=99086aa Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Wed Aug 14 23:34:59 2013 UTC trim: Target SCSI UNMAP command instead of WRITE SAME. * The UNMAP command is theoretically much faster, as it can get many block ranges instead of just a single range. * Furthermore, the ATA TRIM command resembles it much better. * Therefore, fs_trim_data now gets an array of ranges, and we use SCSI UNMAP to trim. * Updated BFS code to collect array ranges to fully support the new fs_trim_data possibilities. ---------------------------------------------------------------------------- diff --git a/headers/os/drivers/Drivers.h b/headers/os/drivers/Drivers.h index ff4e1e0..a854305 100644 --- a/headers/os/drivers/Drivers.h +++ b/headers/os/drivers/Drivers.h @@ -172,9 +172,12 @@ typedef struct { /* B_TRIM_DEVICE data structure */ typedef struct { - off_t offset; /* offset (in bytes) */ - off_t size; - off_t trimmed_size; /* filled on return */ + uint32 range_count; + uint64 trimmed_size; /* filled on return */ + struct range { + uint64 offset; /* offset (in bytes) */ + uint64 size; + } ranges[1]; } fs_trim_data; diff --git a/headers/private/drivers/scsi_cmds.h b/headers/private/drivers/scsi_cmds.h index ea45233..732583d 100644 --- a/headers/private/drivers/scsi_cmds.h +++ b/headers/private/drivers/scsi_cmds.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2010, 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. @@ -185,6 +185,8 @@ #define SCSI_OP_WRITE_BUFFER 0x3b #define SCSI_OP_READ_BUFFER 0x3c #define SCSI_OP_CHANGE_DEFINITION 0x40 +#define SCSI_OP_WRITE_SAME_10 0x41 +#define SCSI_OP_UNMAP 0x42 #define SCSI_OP_READ_SUB_CHANNEL 0x42 #define SCSI_OP_READ_TOC 0x43 #define SCSI_OP_PLAY_MSF 0x47 @@ -457,7 +459,38 @@ typedef struct scsi_cmd_wsame_16 { ); uint8 control; } _PACKED scsi_cmd_wsame_16; - + + +// UNMAP + +typedef struct scsi_cmd_unmap { + uint8 opcode; + LBITFIELD8_2( + anchor : 1, + _reserved1_7 : 7 + ); + uint32 _reserved1; + LBITFIELD8_2( + group_number : 5, + _reserved5_7 : 3 + ); + uint16 length; + uint8 control; +} _PACKED scsi_cmd_unmap; + +struct scsi_unmap_block_descriptor { + uint64 lba; + uint32 block_count; + uint32 _reserved1; +} _PACKED; + +struct scsi_unmap_parameter_list { + uint16 data_length; + uint16 block_data_length; + uint32 _reserved1; + struct scsi_unmap_block_descriptor blocks[1]; +} _PACKED; + // REQUEST SENSE diff --git a/headers/private/drivers/scsi_periph.h b/headers/private/drivers/scsi_periph.h index b879521..9be19ab 100644 --- a/headers/private/drivers/scsi_periph.h +++ b/headers/private/drivers/scsi_periph.h @@ -72,6 +72,10 @@ typedef struct scsi_periph_callbacks { void (*media_changed)(periph_device_cookie cookie, scsi_ccb *request); } scsi_periph_callbacks; +typedef struct scsi_block_range { + uint64 offset; + uint64 size; +} scsi_block_range; // functions provided by this module typedef struct scsi_periph_interface { @@ -119,7 +123,7 @@ typedef struct scsi_periph_interface { 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); + scsi_block_range* ranges, uint32 rangeCount); // *** removable media *** // to be called when a medium change is detected to block subsequent commands diff --git a/headers/private/fs_shell/fssh_drivers.h b/headers/private/fs_shell/fssh_drivers.h index aa63da3..aa67e69 100644 --- a/headers/private/fs_shell/fssh_drivers.h +++ b/headers/private/fs_shell/fssh_drivers.h @@ -215,9 +215,12 @@ typedef struct { /* B_TRIM_DEVICE data structure */ typedef struct { - fssh_off_t offset; /* offset (in bytes) */ - fssh_off_t size; - fssh_off_t trimmed_size; /* filled on return */ + uint32_t range_count; + uint64_t trimmed_size; /* filled on return */ + struct range { + uint64_t offset; /* offset (in bytes) */ + uint64_t size; + } ranges[1]; } fssh_fs_trim_data; diff --git a/headers/private/kernel/util/fs_trim_support.h b/headers/private/kernel/util/fs_trim_support.h new file mode 100644 index 0000000..a9f993c --- /dev/null +++ b/headers/private/kernel/util/fs_trim_support.h @@ -0,0 +1,48 @@ +/* + * Copyright 2013, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Distributed under the terms of the MIT license. + */ +#ifndef _FS_TRIM_SUPPORT_H +#define _FS_TRIM_SUPPORT_H + + +#include <Drivers.h> + +#include <kernel.h> + + +static inline status_t +copy_trim_data_from_user(void* buffer, size_t size, fs_trim_data*& _trimData) +{ + if (!IS_USER_ADDRESS(buffer)) + return B_BAD_ADDRESS; + + uint32 count; + if (user_memcpy(&count, buffer, sizeof(count)) != B_OK) + return B_BAD_ADDRESS; + + size_t bytes = (count - 1) * sizeof(uint64) * 2 + sizeof(fs_trim_data); + if (bytes > size) + return B_BAD_VALUE; + + void* trimBuffer = malloc(bytes); + if (trimBuffer == NULL) + return B_NO_MEMORY; + + if (user_memcpy(trimBuffer, buffer, bytes) != B_OK) + return B_BAD_ADDRESS; + + _trimData = (fs_trim_data*)trimBuffer; + return B_OK; +} + + +static inline status_t +copy_trim_data_to_user(void* buffer, fs_trim_data* trimData) +{ + // Do not copy any ranges + return user_memcpy(buffer, trimData, sizeof(uint64) * 2); +} + + +#endif // _FS_TRIM_SUPPORT_H diff --git a/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp b/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp index c566396..f445764 100644 --- a/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp @@ -21,7 +21,10 @@ #include <string.h> #include <stdlib.h> +#include <AutoDeleter.h> + #include <fs/devfs.h> +#include <util/fs_trim_support.h> #include "dma_resources.h" #include "IORequest.h" @@ -154,7 +157,7 @@ synchronize_cache(das_driver_info *device) static status_t -trim_device(das_driver_info* device, off_t offset, off_t size) +trim_device(das_driver_info* device, fs_trim_data* trimData) { TRACE("trim_device()\n"); @@ -162,10 +165,17 @@ trim_device(das_driver_info* device, off_t offset, off_t size) if (request == NULL) return B_NO_MEMORY; + uint64 trimmedSize = 0; + for (uint32 i = 0; i < trimData->range_count; i++) { + trimmedSize += trimData->ranges[i].size; + } status_t status = sSCSIPeripheral->trim_device(device->scsi_periph_device, - request, offset / device->block_size, size / device->block_size); + request, (scsi_block_range*)&trimData->ranges[0], + trimData->range_count); device->scsi->free_ccb(request); + if (status == B_OK) + trimData->trimmed_size = trimmedSize; return status; } @@ -405,17 +415,19 @@ das_ioctl(void* cookie, uint32 op, void* buffer, size_t length) 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); + fs_trim_data* trimData; + status_t status = copy_trim_data_from_user(buffer, length, + trimData); if (status != B_OK) return status; - trimData.trimmed_size = trimData.size; + MemoryDeleter deleter(trimData); + + status = trim_device(info, trimData); + if (status != B_OK) + return status; - return user_memcpy(buffer, &trimData, sizeof(fs_trim_data)); + return copy_trim_data_to_user(buffer, trimData); } default: diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp index 432df6c..31dd753 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp @@ -1191,19 +1191,28 @@ BlockAllocator::_CheckGroup(int32 groupIndex) const status_t -BlockAllocator::Trim(off_t offset, off_t size, off_t& trimmedSize) +BlockAllocator::Trim(uint64 offset, uint64 size, uint64& trimmedSize) { + const uint32 kTrimRanges = 128; + fs_trim_data* trimData = (fs_trim_data*)malloc(sizeof(fs_trim_data) + + sizeof(uint64) * kTrimRanges); + if (trimData == NULL) + return B_NO_MEMORY; + + MemoryDeleter deleter(trimData); RecursiveLocker locker(fLock); // TODO: take given offset and size into account! int32 lastGroup = fNumGroups - 1; uint32 firstBlock = 0; uint32 firstBit = 0; - off_t currentBlock = 0; + uint64 currentBlock = 0; uint32 blockShift = fVolume->BlockShift(); - off_t firstFree = -1; + uint64 firstFree = 0; size_t freeLength = 0; + + trimData->range_count = 0; trimmedSize = 0; AllocationBlock cached(fVolume); @@ -1217,8 +1226,9 @@ BlockAllocator::Trim(off_t offset, off_t size, off_t& trimmedSize) if (cached.IsUsed(i)) { // Block is in use if (freeLength > 0) { - status_t status = _TrimNext(firstFree << blockShift, - freeLength << blockShift, trimmedSize); + status_t status = _TrimNext(*trimData, kTrimRanges, + firstFree << blockShift, freeLength << blockShift, + false, trimmedSize); if (status != B_OK) return status; @@ -1237,12 +1247,8 @@ BlockAllocator::Trim(off_t offset, off_t size, off_t& trimmedSize) firstBit = 0; } - if (freeLength > 0) { - return _TrimNext(firstFree << blockShift, freeLength << blockShift, - trimmedSize); - } - - return B_OK; + return _TrimNext(*trimData, kTrimRanges, firstFree << blockShift, + freeLength << blockShift, true, trimmedSize); } @@ -2181,21 +2187,44 @@ BlockAllocator::_AddInodeToIndex(Inode* inode) status_t -BlockAllocator::_TrimNext(off_t offset, off_t size, off_t& trimmedSize) +BlockAllocator::_AddTrim(fs_trim_data& trimData, uint32 maxRanges, + uint64 offset, uint64 size) { - PRINT(("_TrimNext(offset %lld, size %lld)\n", offset, size)); + if (trimData.range_count < maxRanges && size > 0) { + trimData.ranges[trimData.range_count].offset = offset; + trimData.ranges[trimData.range_count].size = size; + trimData.range_count++; + return true; + } - fs_trim_data trimData; - trimData.offset = offset; - trimData.size = size; - trimData.trimmed_size = 0; + return false; +} - if (ioctl(fVolume->Device(), B_TRIM_DEVICE, &trimData, - sizeof(fs_trim_data)) != 0) { - return errno; + +status_t +BlockAllocator::_TrimNext(fs_trim_data& trimData, uint32 maxRanges, + uint64 offset, uint64 size, bool force, uint64& trimmedSize) +{ + PRINT(("_TrimNext(index %" B_PRIu32 ", offset %" B_PRIu64 ", size %" + B_PRIu64 ")\n", trimData.range_count, offset, size)); + + bool pushed = _AddTrim(trimData, maxRanges, offset, size); + + if (!pushed || force) { + // Trim now + trimData.trimmed_size = 0; + if (ioctl(fVolume->Device(), B_TRIM_DEVICE, &trimData, + sizeof(fs_trim_data)) != 0) { + return errno; + } + + trimmedSize += trimData.trimmed_size; + trimData.range_count = 0; } - trimmedSize += trimData.trimmed_size; + if (!pushed) + _AddTrim(trimData, maxRanges, offset, size); + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h index 88b9d52..d3da867 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h @@ -46,7 +46,8 @@ public: int32 group, uint16 start, uint16 numBlocks, uint16 minimum, block_run& run); - status_t Trim(off_t offset, off_t size, off_t& trimmedSize); + status_t Trim(uint64 offset, uint64 size, + uint64& trimmedSize); status_t StartChecking(const check_control* control); status_t StopChecking(check_control* control); @@ -83,8 +84,11 @@ private: void _FreeIndices(); status_t _AddInodeToIndex(Inode* inode); status_t _WriteBackCheckBitmap(); - status_t _TrimNext(off_t offset, off_t size, - off_t& trimmedSize); + status_t _AddTrim(fs_trim_data& trimData, uint32 maxRanges, + uint64 offset, uint64 size); + status_t _TrimNext(fs_trim_data& trimData, uint32 maxRanges, + uint64 offset, uint64 size, bool force, + uint64& trimmedSize); static status_t _Initialize(BlockAllocator* self); diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index 1140003..ab68d57 100644 --- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp @@ -20,8 +20,10 @@ // TODO: temporary solution as long as there is no public I/O requests API #ifndef BFS_SHELL # include <io_requests.h> +# include <util/fs_trim_support.h> #endif + #define BFS_IO_SIZE 65536 @@ -623,19 +625,32 @@ bfs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd, Volume* volume = (Volume*)_volume->private_volume; switch (cmd) { +#ifndef BFS_SHELL 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 = volume->Allocator().Trim(trimData.offset, - trimData.size, trimData.trimmed_size); + fs_trim_data* trimData; + status_t status = copy_trim_data_from_user(buffer, bufferLength, + trimData); if (status != B_OK) return status; - return user_memcpy(buffer, &trimData, sizeof(fs_trim_data)); + MemoryDeleter deleter(trimData); + trimData->trimmed_size = 0; + + for (uint32 i = 0; i < trimData->range_count; i++) { + uint64 trimmedSize = 0; + status_t status = volume->Allocator().Trim( + trimData->ranges[i].offset, trimData->ranges[i].size, + trimmedSize); + if (status != B_OK) + return status; + + trimData->trimmed_size += trimmedSize; + } + + return copy_trim_data_to_user(buffer, trimData); } +#endif case BFS_IOCTL_VERSION: { diff --git a/src/add-ons/kernel/generic/scsi_periph/Jamfile b/src/add-ons/kernel/generic/scsi_periph/Jamfile index 2aaa529..5fd764c 100644 --- a/src/add-ons/kernel/generic/scsi_periph/Jamfile +++ b/src/add-ons/kernel/generic/scsi_periph/Jamfile @@ -1,6 +1,6 @@ SubDir HAIKU_TOP src add-ons kernel generic scsi_periph ; -UsePrivateHeaders drivers kernel ; +UsePrivateHeaders drivers kernel shared ; SubDirHdrs $(HAIKU_TOP) src system kernel device_manager ; # disable debug output, if debugging is disabled diff --git a/src/add-ons/kernel/generic/scsi_periph/block.cpp b/src/add-ons/kernel/generic/scsi_periph/block.cpp index 0c6eb0d..7f6cfcd 100644 --- a/src/add-ons/kernel/generic/scsi_periph/block.cpp +++ b/src/add-ons/kernel/generic/scsi_periph/block.cpp @@ -9,9 +9,12 @@ //! Handling of block device -#include "scsi_periph_int.h" #include <string.h> +#include <AutoDeleter.h> + +#include "scsi_periph_int.h" + status_t periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *request) @@ -117,23 +120,53 @@ periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *request) status_t periph_trim_device(scsi_periph_device_info *device, scsi_ccb *request, - uint64 offset, uint64 numBlocks) + scsi_block_range* ranges, uint32 rangeCount) { err_res res; int retries = 0; + size_t unmapBlockSize = (rangeCount - 1) + * sizeof(scsi_unmap_block_descriptor) + + sizeof(scsi_unmap_parameter_list); + + // TODO: check block limits VPD page + // TODO: instead of failing, we should try to complete the request in + // several passes. + if (unmapBlockSize > 65536 || rangeCount == 0) + return B_BAD_VALUE; + + scsi_unmap_parameter_list* unmapBlocks + = (scsi_unmap_parameter_list*)malloc(unmapBlockSize); + if (unmapBlocks == NULL) + return B_NO_MEMORY; + + MemoryDeleter deleter(unmapBlocks); + + // Prepare request data + memset(unmapBlocks, 0, unmapBlockSize); + unmapBlocks->data_length = B_HOST_TO_BENDIAN_INT16(unmapBlockSize - 1); + unmapBlocks->data_length = B_HOST_TO_BENDIAN_INT16(unmapBlockSize - 3); + + for (uint32 i = 0; i < rangeCount; i++) { + unmapBlocks->blocks[i].lba = B_HOST_TO_BENDIAN_INT64( + ranges[i].offset / device->block_size); + unmapBlocks->blocks[i].block_count = B_HOST_TO_BENDIAN_INT32( + ranges[i].size / device->block_size); + } + do { request->flags = SCSI_DIR_OUT; - request->sort = offset; + request->sort = ranges[0].offset / device->block_size; request->timeout = device->std_timeout; - scsi_cmd_wsame_16* cmd = (scsi_cmd_wsame_16*)request->cdb; + scsi_cmd_unmap* cmd = (scsi_cmd_unmap*)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); + cmd->opcode = SCSI_OP_UNMAP; + cmd->length = B_HOST_TO_BENDIAN_INT16(unmapBlockSize); + + request->data = (uint8*)unmapBlocks; + request->data_length = unmapBlockSize; request->cdb_length = sizeof(*cmd); diff --git a/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h b/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h index 30df67a..af032b4 100644 --- a/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h +++ b/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h @@ -78,7 +78,7 @@ status_t periph_handle_free(scsi_periph_handle_info *handle); 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); + scsi_block_range* ranges, uint32 rangeCount); // device.c diff --git a/src/bin/fstrim.cpp b/src/bin/fstrim.cpp index d5dda26..cc0b47f 100644 --- a/src/bin/fstrim.cpp +++ b/src/bin/fstrim.cpp @@ -7,7 +7,7 @@ #include <errno.h> #include <fcntl.h> #include <getopt.h> -#include <limits.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -66,8 +66,9 @@ main(int argc, char** argv) FileDescriptorCloser closer(fd); fs_trim_data trimData; - trimData.offset = 0; - trimData.size = OFF_MAX; + trimData.range_count = 1; + trimData.ranges[0].offset = 0; + trimData.ranges[0].size = UINT64_MAX; trimData.trimmed_size = 0; if (ioctl(fd, B_TRIM_DEVICE, &trimData, sizeof(fs_trim_data)) != 0) { ############################################################################ Commit: 33945c5c8993bedfe46a43a12f27e8178c249dd6 URL: http://cgit.haiku-os.org/haiku/commit/?id=33945c5 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Wed Aug 14 23:40:12 2013 UTC ahci: Pushed TRIM support a tiny bit further. * Now doesn't do anything on SCSI_OP_UNMAP, instead of doing nothing on SCSI_OP_WRITE_SAME_16. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index ecc84d0..f3de1bb 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -51,7 +51,7 @@ AHCIPort::AHCIPort(AHCIController *controller, int index) fTestUnitReadyActive(false), fResetPort(false), fError(false), - fTrim(false) + fTrimSupported(false) { B_INITIALIZE_SPINLOCK(&fSpinlock); fRequestSem = create_sem(1, "ahci request"); @@ -604,7 +604,7 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) if (!fIsATAPI) { fSectorCount = ataData.SectorCount(fUse48BitCommands, true); fSectorSize = ataData.SectorSize(); - fTrim = ataData.data_set_management_support; + fTrimSupported = ataData.data_set_management_support; TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %" B_PRIu32 ", sectors48 %" B_PRIu64 ", size %" B_PRIu64 "\n", ataData.dma_supported != 0, ataData.lba48_supported != 0, @@ -634,7 +634,7 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) TRACE("model number: %s\n", modelNumber); TRACE("serial number: %s\n", serialNumber); TRACE("firmware rev.: %s\n", firmwareRev); - TRACE("trim support: %s\n", fTrim ? "yes" : "no"); + TRACE("trim support: %s\n", fTrimSupported ? "yes" : "no"); // There's not enough space to fit all of the data in. ATA has 40 bytes for // the model number, 20 for the serial number and another 8 for the @@ -787,6 +787,23 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, void +AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) +{ + TRACE("%s unimplemented: TRIM call\n", __func__); + + sata_request* sreq = new(std::nothrow) sata_request(request); + if (sreq == NULL) { + TRACE("out of memory when allocating unmap request\n"); + request->subsys_status = SCSI_REQ_ABORTED; + gSCSI->finished(request, 1); + return; + } + + delete sreq; +} + + +void AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) { FLOW("ExecuteAtaRequest port %d\n", fIndex); @@ -1018,12 +1035,11 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) } break; } - case SCSI_OP_WRITE_SAME_16: + case SCSI_OP_UNMAP: { - const scsi_cmd_wsame_16 *cmd = (const scsi_cmd_wsame_16 *)request->cdb; + const scsi_cmd_unmap* cmd = (const scsi_cmd_unmap*)request->cdb; - // SCSI unmap is used for trim, otherwise we don't support it - if (!cmd->unmap) { + if (!fTrimSupported) { TRACE("%s port %d: unsupported request opcode 0x%02x\n", __func__, fIndex, request->cdb[0]); request->subsys_status = SCSI_REQ_ABORTED; @@ -1031,16 +1047,19 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) break; } - if (!fTrim) { - // Drive doesn't support trim (or atapi) - // Just say it was successful and quit - request->subsys_status = SCSI_REQ_CMP; - } else { - TRACE("%s unimplemented: TRIM call\n", __func__); - // TODO: Make Serial ATA (sata_request?) trim call here. + scsi_unmap_parameter_list* unmapBlocks + = (scsi_unmap_parameter_list*)request->data; + if (unmapBlocks == NULL + || B_BENDIAN_TO_HOST_INT16(cmd->length) != request->data_length + || B_BENDIAN_TO_HOST_INT16(unmapBlocks->data_length) + != request->data_length - 1) { + TRACE("%s port %d: invalid unmap parameter data length\n", + __func__, fIndex); request->subsys_status = SCSI_REQ_ABORTED; + gSCSI->finished(request, 1); + } else { + ScsiUnmap(request, unmapBlocks); } - gSCSI->finished(request, 1); break; } default: diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h index 962e5f7..f89a622 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h @@ -36,6 +36,8 @@ private: void ScsiReadCapacity16(scsi_ccb *request); void ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, bool isWrite); void ScsiSynchronizeCache(scsi_ccb *request); + void ScsiUnmap(scsi_ccb* request, + struct scsi_unmap_parameter_list* unmapBlocks); void ExecuteSataRequest(sata_request *request, bool isWrite = false); @@ -71,7 +73,7 @@ private: bool fTestUnitReadyActive; bool fResetPort; bool fError; - bool fTrim; + bool fTrimSupported; volatile fis * fFIS; volatile command_list_entry * fCommandList; ############################################################################ Commit: 13e72c9a72945449ff77fcd56d7d0868e159641e URL: http://cgit.haiku-os.org/haiku/commit/?id=13e72c9 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Wed Sep 18 21:04:21 2013 UTC ahci: Minor cleanup. * Mostly utilized ATACommands.h ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index f3de1bb..e0f1c39 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -13,6 +13,7 @@ #include <ByteOrder.h> #include <KernelExport.h> +#include <ATACommands.h> #include <ATAInfoBlock.h> #include "ahci_controller.h" @@ -358,8 +359,8 @@ AHCIPort::InterruptErrorHandler(uint32 is) uint32 ci = fRegs->ci; if (!fTestUnitReadyActive) { - TRACE("AHCIPort::InterruptErrorHandler port %d, " - "fCommandsActive 0x%08" B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", fIndex, + TRACE("AHCIPort::InterruptErrorHandler port %d, fCommandsActive 0x%08" + B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", fIndex, fCommandsActive, is, ci); TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts); @@ -563,7 +564,8 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) sata_request sreq; sreq.set_data(&ataData, sizeof(ataData)); - sreq.set_ata_cmd(fIsATAPI ? 0xa1 : 0xec); // Identify (Packet) Device + sreq.set_ata_cmd(fIsATAPI + ? ATA_COMMAND_IDENTIFY_PACKET_DEVICE : ATA_COMMAND_IDENTIFY_DEVICE); ExecuteSataRequest(&sreq); sreq.wait_for_completion(); @@ -671,7 +673,8 @@ AHCIPort::ScsiSynchronizeCache(scsi_ccb *request) return; } - sreq->set_ata_cmd(fUse48BitCommands ? 0xea : 0xe7); // Flush Cache + sreq->set_ata_cmd(fUse48BitCommands + ? ATA_COMMAND_FLUSH_CACHE_EXT : ATA_COMMAND_FLUSH_CACHE); ExecuteSataRequest(sreq); } @@ -771,7 +774,9 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, } if (lba > MAX_SECTOR_LBA_48) panic("achi: ScsiReadWrite position too large for 48-bit LBA\n"); - sreq->set_ata48_cmd(isWrite ? 0x35 : 0x25, lba, sectorCount); + sreq->set_ata48_cmd( + isWrite ? ATA_COMMAND_WRITE_DMA_EXT : ATA_COMMAND_READ_DMA_EXT, + lba, sectorCount); } else { if (sectorCount > 256) { panic("ahci: ScsiReadWrite length too large, %lu sectors", @@ -779,7 +784,8 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, } if (lba > MAX_SECTOR_LBA_28) panic("achi: ScsiReadWrite position too large for normal LBA\n"); - sreq->set_ata28_cmd(isWrite ? 0xca : 0xc8, lba, sectorCount); + sreq->set_ata28_cmd(isWrite + ? ATA_COMMAND_WRITE_DMA : ATA_COMMAND_READ_DMA, lba, sectorCount); } ExecuteSataRequest(sreq, isWrite); @@ -799,6 +805,7 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) return; } + sreq->set_ata_cmd(ATA_COMMAND_DATA_SET_MANAGEMENT); delete sreq; } @@ -1074,7 +1081,6 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) uchar AHCIPort::ScsiAbortRequest(scsi_ccb *request) { - return SCSI_REQ_CMP; } diff --git a/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp b/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp index 9bd871b..2f5a2d2 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp @@ -10,6 +10,9 @@ #include "scsi_cmds.h" +#define FIS_TYPE_REGISTER_HOST_TO_DEVICE 0x27 + + sata_request::sata_request() : fCcb(NULL), @@ -54,7 +57,7 @@ void sata_request::set_ata_cmd(uint8 command) { memset(fFis, 0, sizeof(fFis)); - fFis[0] = 0x27; + fFis[0] = FIS_TYPE_REGISTER_HOST_TO_DEVICE; fFis[1] = 0x80; fFis[2] = command; } ############################################################################ Commit: d82e6bcf6b00372ab17739d91d169c9ef2952d79 URL: http://cgit.haiku-os.org/haiku/commit/?id=d82e6bc Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Sun Oct 27 22:22:50 2013 UTC ahci: Use get_memory_map_etc(). * Simplifies code a bit. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index e0f1c39..620c1f3 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -434,16 +434,20 @@ status_t AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize) { - int peMax = prdMax + 1; - physical_entry pe[peMax]; - if (get_memory_map(data, dataSize, pe, peMax ) < B_OK) { - TRACE("AHCIPort::FillPrdTable get_memory_map failed\n"); + int maxEntries = prdMax + 1; + physical_entry entries[maxEntries]; + uint32 entriesUsed = maxEntries; + + status_t status = get_memory_map_etc(B_CURRENT_TEAM, data, dataSize, + entries, &entriesUsed); + if (status != B_OK) { + TRACE("AHCIPort::FillPrdTable get_memory_map() failed: %s\n", + strerror(status)); return B_ERROR; } - int peUsed; - for (peUsed = 0; pe[peUsed].size; peUsed++) - ; - return FillPrdTable(prdTable, prdCount, prdMax, pe, peUsed, dataSize); + + return FillPrdTable(prdTable, prdCount, prdMax, entries, entriesUsed, + dataSize); } ############################################################################ Commit: 6317a4c399354af8180690daea02de8dc9dc328f URL: http://cgit.haiku-os.org/haiku/commit/?id=6317a4c Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Sun Oct 27 22:28:38 2013 UTC scsi_periph: fixed copy&paste error in periph_trim_device(). ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/generic/scsi_periph/block.cpp b/src/add-ons/kernel/generic/scsi_periph/block.cpp index 7f6cfcd..8e1d330 100644 --- a/src/add-ons/kernel/generic/scsi_periph/block.cpp +++ b/src/add-ons/kernel/generic/scsi_periph/block.cpp @@ -145,7 +145,8 @@ periph_trim_device(scsi_periph_device_info *device, scsi_ccb *request, // Prepare request data memset(unmapBlocks, 0, unmapBlockSize); unmapBlocks->data_length = B_HOST_TO_BENDIAN_INT16(unmapBlockSize - 1); - unmapBlocks->data_length = B_HOST_TO_BENDIAN_INT16(unmapBlockSize - 3); + unmapBlocks->block_data_length + = B_HOST_TO_BENDIAN_INT16(unmapBlockSize - 7); for (uint32 i = 0; i < rangeCount; i++) { unmapBlocks->blocks[i].lba = B_HOST_TO_BENDIAN_INT64( ############################################################################ Commit: e858a6b2a0e4ee1c8c80c09b1f3ecfef04e8025e URL: http://cgit.haiku-os.org/haiku/commit/?id=e858a6b Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Mon Oct 28 00:05:47 2013 UTC ahci: WIP of implementing trim command. * Data Set Management specific bits are still missing. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index 620c1f3..99d2da6 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -15,6 +15,7 @@ #include <ATACommands.h> #include <ATAInfoBlock.h> +#include <AutoDeleter.h> #include "ahci_controller.h" #include "ahci_tracing.h" @@ -801,7 +802,7 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) { TRACE("%s unimplemented: TRIM call\n", __func__); - sata_request* sreq = new(std::nothrow) sata_request(request); + sata_request* sreq = new(std::nothrow) sata_request(); if (sreq == NULL) { TRACE("out of memory when allocating unmap request\n"); request->subsys_status = SCSI_REQ_ABORTED; @@ -809,12 +810,55 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) return; } + // Determine how many ranges we'll need + // We assume that the SCSI unmap ranges cannot be merged together + uint32 scsiRangeCount = unmapBlocks->block_data_length + / sizeof(scsi_unmap_block_descriptor); + uint32 lbaRangeCount = 0; + for (uint32 i = 0; i < scsiRangeCount; i++) { + lbaRangeCount += ((uint32)B_BENDIAN_TO_HOST_INT32( + unmapBlocks->blocks[i].block_count) + 65534) / 65535; + } + + uint32 lbaRangesSize = lbaRangeCount * sizeof(uint64); + uint64* lbaRanges + = (uint64*)malloc(lbaRangesSize); + if (lbaRanges == NULL) { + TRACE("out of memory when allocating %" B_PRIu32 " unmap ranges\n", + lbaRangeCount); + request->subsys_status = SCSI_REQ_ABORTED; + gSCSI->finished(request, 1); + return; + } + + MemoryDeleter deleter(lbaRanges); + + for (uint32 i = 0, scsiIndex = 0; scsiIndex < scsiRangeCount; scsiIndex++) { + uint64 lba = (uint64)B_BENDIAN_TO_HOST_INT64( + unmapBlocks->blocks[scsiIndex].lba); + uint64 bytesLeft = (uint32)B_BENDIAN_TO_HOST_INT32( + unmapBlocks->blocks[scsiIndex].block_count); + while (bytesLeft > 0) { + uint16 blocks = bytesLeft > 65535 ? 65535 : (uint16)bytesLeft; + lbaRanges[i++] = B_HOST_TO_LENDIAN_INT64( + ((uint64)blocks << 48) | lba); + lba += blocks; + } + } + sreq->set_ata_cmd(ATA_COMMAND_DATA_SET_MANAGEMENT); - delete sreq; + sreq->set_data(lbaRanges, lbaRangesSize); + + bool success = ExecuteSataRequest(sreq); + + request->data_resid = 0; + request->device_status = SCSI_STATUS_GOOD; + request->subsys_status = success ? SCSI_REQ_CMP : SCSI_REQ_CMP_ERR; + gSCSI->finished(request, 1); } -void +bool AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) { FLOW("ExecuteAtaRequest port %d\n", fIndex); @@ -858,7 +902,7 @@ AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) ResetPort(); FinishTransfer(); request->abort(); - return; + return false; } cpu_status cpu = disable_interrupts(); @@ -902,9 +946,11 @@ AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) if (status == B_TIMED_OUT) { TRACE("ExecuteAtaRequest port %d: device timeout\n", fIndex); request->abort(); - } else { - request->finish(tfd, bytesTransfered); + return false; } + + request->finish(tfd, bytesTransfered); + return true; } diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h index f89a622..7ac542c 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h @@ -39,7 +39,7 @@ private: void ScsiUnmap(scsi_ccb* request, struct scsi_unmap_parameter_list* unmapBlocks); - void ExecuteSataRequest(sata_request *request, bool isWrite = false); + bool ExecuteSataRequest(sata_request *request, bool isWrite = false); void ResetDevice(); status_t ResetPort(bool forceDeviceReset = false); ############################################################################ Commit: 10deaef118d90eb9af9f78c6432db502d42305ab URL: http://cgit.haiku-os.org/haiku/commit/?id=10deaef Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Mon Oct 28 22:24:21 2013 UTC ahci: Added missing wait_for_completion(). * Thanks Marcus! * That made the return code for ExecuteSataRequest() pretty much useless, so I removed it again. * Also, a delete sreq was missing; I now allocate it on the stack instead. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index 99d2da6..45ebc9c 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -802,14 +802,6 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) { TRACE("%s unimplemented: TRIM call\n", __func__); - sata_request* sreq = new(std::nothrow) sata_request(); - if (sreq == NULL) { - TRACE("out of memory when allocating unmap request\n"); - request->subsys_status = SCSI_REQ_ABORTED; - gSCSI->finished(request, 1); - return; - } - // Determine how many ranges we'll need // We assume that the SCSI unmap ranges cannot be merged together uint32 scsiRangeCount = unmapBlocks->block_data_length @@ -846,19 +838,26 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) } } - sreq->set_ata_cmd(ATA_COMMAND_DATA_SET_MANAGEMENT); - sreq->set_data(lbaRanges, lbaRangesSize); + sata_request sreq; + sreq.set_ata_cmd(ATA_COMMAND_DATA_SET_MANAGEMENT); + sreq.set_data(lbaRanges, lbaRangesSize); + + ExecuteSataRequest(&sreq); + sreq.wait_for_completion(); - bool success = ExecuteSataRequest(sreq); + if ((sreq.completion_status() & ATA_ERR) != 0) { + TRACE("trim failed (%" B_PRIu32 " ranges)!", lbaRangeCount); + request->subsys_status = SCSI_REQ_CMP_ERR; + } else + request->subsys_status = SCSI_REQ_CMP; request->data_resid = 0; request->device_status = SCSI_STATUS_GOOD; - request->subsys_status = success ? SCSI_REQ_CMP : SCSI_REQ_CMP_ERR; gSCSI->finished(request, 1); } -bool +void AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) { FLOW("ExecuteAtaRequest port %d\n", fIndex); @@ -902,7 +901,7 @@ AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) ResetPort(); FinishTransfer(); request->abort(); - return false; + return; } cpu_status cpu = disable_interrupts(); @@ -946,11 +945,10 @@ AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) if (status == B_TIMED_OUT) { TRACE("ExecuteAtaRequest port %d: device timeout\n", fIndex); request->abort(); - return false; + return; } request->finish(tfd, bytesTransfered); - return true; } diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h index 7ac542c..f89a622 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h @@ -39,7 +39,7 @@ private: void ScsiUnmap(scsi_ccb* request, struct scsi_unmap_parameter_list* unmapBlocks); - bool ExecuteSataRequest(sata_request *request, bool isWrite = false); + void ExecuteSataRequest(sata_request *request, bool isWrite = false); void ResetDevice(); status_t ResetPort(bool forceDeviceReset = false); ############################################################################ Commit: fd88486a317f6ec0ab9c0cb755aebde1bb0ead0f URL: http://cgit.haiku-os.org/haiku/commit/?id=fd88486 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Mon Oct 28 22:36:27 2013 UTC ahci: Set the command bits as required. * The trim command should be functional now, but it's completely untested at this point. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index 45ebc9c..d50ce71 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -839,7 +839,8 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) } sata_request sreq; - sreq.set_ata_cmd(ATA_COMMAND_DATA_SET_MANAGEMENT); + sreq.set_ata48_cmd(ATA_COMMAND_DATA_SET_MANAGEMENT, 0, + (lbaRangesSize + 511) / 512); sreq.set_data(lbaRanges, lbaRangesSize); ExecuteSataRequest(&sreq); ############################################################################ Commit: 930cb4206be505be32df1872254f54407af9c1c0 URL: http://cgit.haiku-os.org/haiku/commit/?id=930cb42 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Mon Oct 28 22:45:28 2013 UTC ahci: Minor cleanup. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index d50ce71..3a5611d 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2008-2013 Haiku, Inc. All rights reserved. * Copyright 2007-2009, Marcus Overhagen. All rights reserved. * Distributed under the terms of the MIT License. */ @@ -36,7 +37,7 @@ #define RWTRACE(a...) -AHCIPort::AHCIPort(AHCIController *controller, int index) +AHCIPort::AHCIPort(AHCIController* controller, int index) : fController(controller), fIndex(index), @@ -77,24 +78,25 @@ AHCIPort::Init1() + sizeof(fis) + sizeof(command_table) + sizeof(prd) * PRD_TABLE_ENTRY_COUNT; - char *virtAddr; + char* virtAddr; phys_addr_t physAddr; + char name[32]; + snprintf(name, sizeof(name), "AHCI port %d", fIndex); - fArea = alloc_mem((void **)&virtAddr, &physAddr, size, 0, - "some AHCI port"); + fArea = alloc_mem((void**)&virtAddr, &physAddr, size, 0, name); if (fArea < B_OK) { TRACE("failed allocating memory for port %d\n", fIndex); return fArea; } memset(virtAddr, 0, size); - fCommandList = (command_list_entry *)virtAddr; + fCommandList = (command_list_entry*)virtAddr; virtAddr += sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT; - fFIS = (fis *)virtAddr; + fFIS = (fis*)virtAddr; virtAddr += sizeof(fis); - fCommandTable = (command_table *)virtAddr; + fCommandTable = (command_table*)virtAddr; virtAddr += sizeof(command_table); - fPRDTable = (prd *)virtAddr; + fPRDTable = (prd*)virtAddr; TRACE("PRD table is at %p\n", fPRDTable); fRegs->clb = LO32(physAddr); @@ -303,8 +305,8 @@ AHCIPort::PostReset() if (!fTestUnitReadyActive) { TRACE("device signature 0x%08" B_PRIx32 " (%s)\n", fRegs->sig, - (fRegs->sig == 0xeb140101) ? "ATAPI" : (fRegs->sig == 0x00000101) ? - "ATA" : "unknown"); + fRegs->sig == 0xeb140101 ? "ATAPI" : fRegs->sig == 0x00000101 + ? "ATA" : "unknown"); } return B_OK; @@ -341,9 +343,9 @@ AHCIPort::Interrupt() uint32 ci = fRegs->ci; - RWTRACE("[%lld] %ld AHCIPort::Interrupt port %d, fCommandsActive 0x%08" B_PRIx32 ", " - "is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", system_time(), find_thread(NULL), - fIndex, fCommandsActive, is, ci); + RWTRACE("[%lld] %ld AHCIPort::Interrupt port %d, fCommandsActive 0x%08" + B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", + system_time(), find_thread(NULL), fIndex, fCommandsActive, is, ci); acquire_spinlock(&fSpinlock); if ((fCommandsActive & 1) && !(ci & 1)) { @@ -432,8 +434,8 @@ AHCIPort::InterruptErrorHandler(uint32 is) status_t -AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, - const void *data, size_t dataSize) +AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax, + const void* data, size_t dataSize) { int maxEntries = prdMax + 1; physical_entry entries[maxEntries]; @@ -453,8 +455,8 @@ AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, status_t -AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, - const physical_entry *sgTable, int sgCount, size_t dataSize) +AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax, + const physical_entry* sgTable, int sgCount, size_t dataSize) { *prdCount = 0; while (sgCount > 0 && dataSize > 0) { @@ -510,7 +512,7 @@ AHCIPort::StartTransfer() status_t -AHCIPort::WaitForTransfer(int *tfd, bigtime_t timeout) +AHCIPort::WaitForTransfer(int* tfd, bigtime_t timeout) { status_t result = acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, timeout); @@ -541,7 +543,7 @@ AHCIPort::FinishTransfer() void -AHCIPort::ScsiTestUnitReady(scsi_ccb *request) +AHCIPort::ScsiTestUnitReady(scsi_ccb* request) { TRACE("AHCIPort::ScsiTestUnitReady port %d\n", fIndex); request->subsys_status = SCSI_REQ_CMP; @@ -550,17 +552,18 @@ AHCIPort::ScsiTestUnitReady(scsi_ccb *request) void -AHCIPort::ScsiInquiry(scsi_ccb *request) +AHCIPort::ScsiInquiry(scsi_ccb* request) { TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex); - const scsi_cmd_inquiry *cmd = (const scsi_cmd_inquiry *)request->cdb; + const scsi_cmd_inquiry* cmd = (const scsi_cmd_inquiry*)request->cdb; scsi_res_inquiry scsiData; ata_device_infoblock ataData; ASSERT(sizeof(ataData) == 512); - if (cmd->evpd || cmd->page_code || request->data_length < sizeof(scsiData)) { + if (cmd->evpd || cmd->page_code + || request->data_length < sizeof(scsiData)) { TRACE("invalid request\n"); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); @@ -582,7 +585,7 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) } /* - uint8 *data = (uint8*) &ataData; + uint8* data = (uint8*) &ataData; for (int i = 0; i < 512; i += 8) { TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); @@ -666,11 +669,11 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) void -AHCIPort::ScsiSynchronizeCache(scsi_ccb *request) +AHCIPort::ScsiSynchronizeCache(scsi_ccb* request) { //TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex); - sata_request *sreq = new(std::nothrow) sata_request(request); + sata_request* sreq = new(std::nothrow) sata_request(request); if (sreq == NULL) { TRACE("out of memory when allocating sync request\n"); request->subsys_status = SCSI_REQ_ABORTED; @@ -685,11 +688,12 @@ AHCIPort::ScsiSynchronizeCache(scsi_ccb *request) void -AHCIPort::ScsiReadCapacity(scsi_ccb *request) +AHCIPort::ScsiReadCapacity(scsi_ccb* request) { TRACE("AHCIPort::ScsiReadCapacity port %d\n", fIndex); - const scsi_cmd_read_capacity *cmd = (const scsi_cmd_read_capacity *)request->cdb; + const scsi_cmd_read_capacity* cmd + = (const scsi_cmd_read_capacity*)request->cdb; scsi_res_read_capacity scsiData; if (cmd->pmi || cmd->lba || request->data_length < sizeof(scsiData)) { @@ -721,11 +725,10 @@ AHCIPort::ScsiReadCapacity(scsi_ccb *request) void -AHCIPort::ScsiReadCapacity16(scsi_ccb *request) +AHCIPort::ScsiReadCapacity16(scsi_ccb* request) { TRACE("AHCIPort::ScsiReadCapacity16 port %d\n", fIndex); - //const scsi_cmd_read_capacity_long *cmd = (const scsi_cmd_read_capacity_long *)request->cdb; scsi_res_read_capacity_long scsiData; TRACE("SectorSize %" B_PRIu32 ", SectorCount 0x%" B_PRIx64 "\n", @@ -746,7 +749,7 @@ AHCIPort::ScsiReadCapacity16(scsi_ccb *request) void -AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, +AHCIPort::ScsiReadWrite(scsi_ccb* request, uint64 lba, size_t sectorCount, bool isWrite) { RWTRACE("[%lld] %ld ScsiReadWrite: position %llu, size %lu, isWrite %d\n", @@ -764,7 +767,7 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, #endif ASSERT(request->data_length == sectorCount * 512); - sata_request *sreq = new(std::nothrow) sata_request(request); + sata_request* sreq = new(std::nothrow) sata_request(request); if (sreq == NULL) { TRACE("out of memory when allocating read/write request\n"); request->subsys_status = SCSI_REQ_ABORTED; @@ -813,8 +816,7 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) } uint32 lbaRangesSize = lbaRangeCount * sizeof(uint64); - uint64* lbaRanges - = (uint64*)malloc(lbaRangesSize); + uint64* lbaRanges = (uint64*)malloc(lbaRangesSize); if (lbaRanges == NULL) { TRACE("out of memory when allocating %" B_PRIu32 " unmap ranges\n", lbaRangeCount); @@ -859,7 +861,7 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) void -AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) +AHCIPort::ExecuteSataRequest(sata_request* request, bool isWrite) { FLOW("ExecuteAtaRequest port %d\n", fIndex); @@ -881,13 +883,13 @@ AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) fCommandList->prdtl_flags_cfl = 0; fCommandList->cfl = 5; // 20 bytes, length in DWORDS - memcpy((char *)fCommandTable->cfis, request->fis(), 20); + memcpy((char*)fCommandTable->cfis, request->fis(), 20); fTestUnitReadyActive = request->is_test_unit_ready(); if (request->is_atapi()) { // ATAPI PACKET is a 12 or 16 byte SCSI command - memset((char *)fCommandTable->acmd, 0, 32); - memcpy((char *)fCommandTable->acmd, request->ccb()->cdb, + memset((char*)fCommandTable->acmd, 0, 32); + memcpy((char*)fCommandTable->acmd, request->ccb()->cdb, request->ccb()->cdb_length); fCommandList->a = 1; } @@ -954,7 +956,7 @@ AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) void -AHCIPort::ScsiExecuteRequest(scsi_ccb *request) +AHCIPort::ScsiExecuteRequest(scsi_ccb* request) { // TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); @@ -977,7 +979,7 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) // TRACE("AHCIPort::ScsiExecuteRequest ATAPI: port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); - sata_request *sreq = new(std::nothrow) sata_request(request); + sata_request* sreq = new(std::nothrow) sata_request(request); if (sreq == NULL) { TRACE("out of memory when allocating atapi request\n"); request->subsys_status = SCSI_REQ_ABORTED; @@ -986,7 +988,7 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) } sreq->set_atapi_cmd(request->data_length); -// uint8 *data = (uint8*) sreq->ccb()->cdb; +// uint8* data = (uint8*) sreq->ccb()->cdb; // for (int i = 0; i < 16; i += 8) { // TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); // } @@ -1032,7 +1034,7 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) case SCSI_OP_READ_6: case SCSI_OP_WRITE_6: { - const scsi_cmd_rw_6 *cmd = (const scsi_cmd_rw_6 *)request->cdb; + const scsi_cmd_rw_6* cmd = (const scsi_cmd_rw_6*)request->cdb; uint32 position = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba; size_t length = cmd->length != 0 ? cmd->length : 256; @@ -1043,7 +1045,7 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) case SCSI_OP_READ_10: case SCSI_OP_WRITE_10: { - const scsi_cmd_rw_10 *cmd = (const scsi_cmd_rw_10 *)request->cdb; + const scsi_cmd_rw_10* cmd = (const scsi_cmd_rw_10*)request->cdb; uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10; @@ -1060,7 +1062,7 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) case SCSI_OP_READ_12: case SCSI_OP_WRITE_12: { - const scsi_cmd_rw_12 *cmd = (const scsi_cmd_rw_12 *)request->cdb; + const scsi_cmd_rw_12* cmd = (const scsi_cmd_rw_12*)request->cdb; uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12; @@ -1077,7 +1079,7 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) case SCSI_OP_READ_16: case SCSI_OP_WRITE_16: { - const scsi_cmd_rw_16 *cmd = (const scsi_cmd_rw_16 *)request->cdb; + const scsi_cmd_rw_16* cmd = (const scsi_cmd_rw_16*)request->cdb; uint64 position = B_BENDIAN_TO_HOST_INT64(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_16; @@ -1128,14 +1130,14 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) uchar -AHCIPort::ScsiAbortRequest(scsi_ccb *request) +AHCIPort::ScsiAbortRequest(scsi_ccb* request) { return SCSI_REQ_CMP; } uchar -AHCIPort::ScsiTerminateRequest(scsi_ccb *request) +AHCIPort::ScsiTerminateRequest(scsi_ccb* request) { return SCSI_REQ_CMP; } @@ -1149,12 +1151,13 @@ AHCIPort::ScsiResetDevice() void -AHCIPort::ScsiGetRestrictions(bool *isATAPI, bool *noAutoSense, - uint32 *maxBlocks) +AHCIPort::ScsiGetRestrictions(bool* isATAPI, bool* noAutoSense, + uint32* maxBlocks) { *isATAPI = fIsATAPI; *noAutoSense = fIsATAPI; // emulated auto sense for ATA, but not ATAPI *maxBlocks = fUse48BitCommands ? 65536 : 256; TRACE("AHCIPort::ScsiGetRestrictions port %d: isATAPI %d, noAutoSense %d, " - "maxBlocks %" B_PRIu32 "\n", fIndex, *isATAPI, *noAutoSense, *maxBlocks); + "maxBlocks %" B_PRIu32 "\n", fIndex, *isATAPI, *noAutoSense, + *maxBlocks); } diff --git a/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp b/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp index 2f5a2d2..d5cfd82 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp @@ -59,6 +59,7 @@ sata_request::set_ata_cmd(uint8 command) memset(fFis, 0, sizeof(fFis)); fFis[0] = FIS_TYPE_REGISTER_HOST_TO_DEVICE; fFis[1] = 0x80; + // This is a command fFis[2] = command; } @@ -71,6 +72,7 @@ sata_request::set_ata28_cmd(uint8 command, uint32 lba, uint8 sectorCount) fFis[5] = (lba >> 8) & 0xff; fFis[6] = (lba >> 16) & 0xff; fFis[7] = 0x40 | ((lba >> 24) & 0x0f); + // device fFis[12] = sectorCount & 0xff; } @@ -83,6 +85,7 @@ sata_request::set_ata48_cmd(uint8 command, uint64 lba, uint16 sectorCount) fFis[5] = (lba >> 8) & 0xff; fFis[6] = (lba >> 16) & 0xff; fFis[7] = 0x40; + // device fFis[8] = (lba >> 24) & 0xff; fFis[9] = (lba >> 32) & 0xff; fFis[10] = (lba >> 40) & 0xff; ############################################################################ Commit: 2e4e1eb2d9d4505cd716151de281319a03695f36 URL: http://cgit.haiku-os.org/haiku/commit/?id=2e4e1eb Author: Axel Doerfler <axeld@xxxxxxxxxxxxxxxx> Date: Tue Oct 29 13:25:15 2013 UTC Committer: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Commit-Date: Thu Nov 7 18:05:41 2013 UTC ahci: fixed endless loop, and missing bit. * The value for trim is bit 0, not 0; added sata_request::SetFeature() to change this. * The lba range fill loop never ended. * Thanks to Marcus for proof-reading! ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index 3a5611d..00f17eb 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -837,12 +837,14 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) lbaRanges[i++] = B_HOST_TO_LENDIAN_INT64( ((uint64)blocks << 48) | lba); lba += blocks; + bytesLeft -= blocks; } } sata_request sreq; sreq.set_ata48_cmd(ATA_COMMAND_DATA_SET_MANAGEMENT, 0, (lbaRangesSize + 511) / 512); + sreq.SetFeature(1); sreq.set_data(lbaRanges, lbaRangesSize); ExecuteSataRequest(&sreq); diff --git a/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp b/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp index d5cfd82..2fe8b21 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp @@ -95,6 +95,14 @@ sata_request::set_ata48_cmd(uint8 command, uint64 lba, uint16 sectorCount) void +sata_request::SetFeature(uint16 feature) +{ + fFis[3] = (uint8)(feature & 0xff); + fFis[11] = (uint8)(feature >> 8); +} + + +void sata_request::set_atapi_cmd(size_t transferLength) { fIsATAPI = true; diff --git a/src/add-ons/kernel/busses/scsi/ahci/sata_request.h b/src/add-ons/kernel/busses/scsi/ahci/sata_request.h index 71550f6..61191be 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/sata_request.h +++ b/src/add-ons/kernel/busses/scsi/ahci/sata_request.h @@ -20,6 +20,7 @@ public: void set_ata_cmd(uint8 command); void set_ata28_cmd(uint8 command, uint32 lba, uint8 sectorCount); void set_ata48_cmd(uint8 command, uint64 lba, uint16 sectorCount); + void SetFeature(uint16 feature); void set_atapi_cmd(size_t transferLength); bool is_atapi(); ############################################################################ Commit: dbeb6b56b467bbbe02be03f8ea813708c0fd2443 URL: http://cgit.haiku-os.org/haiku/commit/?id=dbeb6b5 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Tue Oct 29 21:53:24 2013 UTC ahci: Fixed braindead variable naming. * Again, thanks Marcus! ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index 00f17eb..e170d33 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -830,14 +830,14 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) for (uint32 i = 0, scsiIndex = 0; scsiIndex < scsiRangeCount; scsiIndex++) { uint64 lba = (uint64)B_BENDIAN_TO_HOST_INT64( unmapBlocks->blocks[scsiIndex].lba); - uint64 bytesLeft = (uint32)B_BENDIAN_TO_HOST_INT32( + uint64 blocksLeft = (uint32)B_BENDIAN_TO_HOST_INT32( unmapBlocks->blocks[scsiIndex].block_count); - while (bytesLeft > 0) { - uint16 blocks = bytesLeft > 65535 ? 65535 : (uint16)bytesLeft; + while (blocksLeft > 0) { + uint16 blocks = blocksLeft > 65535 ? 65535 : (uint16)blocksLeft; lbaRanges[i++] = B_HOST_TO_LENDIAN_INT64( ((uint64)blocks << 48) | lba); lba += blocks; - bytesLeft -= blocks; + blocksLeft -= blocks; } } ############################################################################ Commit: 79cb543ae0f372eeb1ff7a9c108d19b9150e76c7 URL: http://cgit.haiku-os.org/haiku/commit/?id=79cb543 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Tue Oct 29 22:29:06 2013 UTC ahci: Minor coding style cleanup. * Renamed some methods to camel case. * Replaced coding error panics with ASSERTs. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index e170d33..652f153 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -571,13 +571,13 @@ AHCIPort::ScsiInquiry(scsi_ccb* request) } sata_request sreq; - sreq.set_data(&ataData, sizeof(ataData)); - sreq.set_ata_cmd(fIsATAPI + sreq.SetData(&ataData, sizeof(ataData)); + sreq.SetATACommand(fIsATAPI ? ATA_COMMAND_IDENTIFY_PACKET_DEVICE : ATA_COMMAND_IDENTIFY_DEVICE); ExecuteSataRequest(&sreq); - sreq.wait_for_completion(); + sreq.WaitForCompletion(); - if (sreq.completion_status() & ATA_ERR) { + if ((sreq.CompletionStatus() & ATA_ERR) != 0) { TRACE("identify device failed\n"); request->subsys_status = SCSI_REQ_CMP_ERR; gSCSI->finished(request, 1); @@ -585,7 +585,7 @@ AHCIPort::ScsiInquiry(scsi_ccb* request) } /* - uint8* data = (uint8*) &ataData; + uint8* data = (uint8*)&ataData; for (int i = 0; i < 512; i += 8) { TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); @@ -681,7 +681,7 @@ AHCIPort::ScsiSynchronizeCache(scsi_ccb* request) return; } - sreq->set_ata_cmd(fUse48BitCommands + sreq->SetATACommand(fUse48BitCommands ? ATA_COMMAND_FLUSH_CACHE_EXT : ATA_COMMAND_FLUSH_CACHE); ExecuteSataRequest(sreq); } @@ -782,7 +782,7 @@ AHCIPort::ScsiReadWrite(scsi_ccb* request, uint64 lba, size_t sectorCount, } if (lba > MAX_SECTOR_LBA_48) panic("achi: ScsiReadWrite position too large for 48-bit LBA\n"); - sreq->set_ata48_cmd( + sreq->SetATA48Command( isWrite ? ATA_COMMAND_WRITE_DMA_EXT : ATA_COMMAND_READ_DMA_EXT, lba, sectorCount); } else { @@ -792,7 +792,7 @@ AHCIPort::ScsiReadWrite(scsi_ccb* request, uint64 lba, size_t sectorCount, } if (lba > MAX_SECTOR_LBA_28) panic("achi: ScsiReadWrite position too large for normal LBA\n"); - sreq->set_ata28_cmd(isWrite + sreq->SetATA28Command(isWrite ? ATA_COMMAND_WRITE_DMA : ATA_COMMAND_READ_DMA, lba, sectorCount); } @@ -842,15 +842,15 @@ AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) } sata_request sreq; - sreq.set_ata48_cmd(ATA_COMMAND_DATA_SET_MANAGEMENT, 0, + sreq.SetATA48Command(ATA_COMMAND_DATA_SET_MANAGEMENT, 0, (lbaRangesSize + 511) / 512); sreq.SetFeature(1); - sreq.set_data(lbaRanges, lbaRangesSize); + sreq.SetData(lbaRanges, lbaRangesSize); ExecuteSataRequest(&sreq); - sreq.wait_for_completion(); + sreq.WaitForCompletion(); - if ((sreq.completion_status() & ATA_ERR) != 0) { + if ((sreq.CompletionStatus() & ATA_ERR) != 0) { TRACE("trim failed (%" B_PRIu32 " ranges)!", lbaRangeCount); request->subsys_status = SCSI_REQ_CMP_ERR; } else @@ -871,13 +871,13 @@ AHCIPort::ExecuteSataRequest(sata_request* request, bool isWrite) int prdEntrys; - if (request->ccb() && request->ccb()->data_length) { + if (request->CCB() && request->CCB()->data_length) { FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, - request->ccb()->sg_list, request->ccb()->sg_count, - request->ccb()->data_length); - } else if (request->data() && request->size()) { + request->CCB()->sg_list, request->CCB()->sg_count, + request->CCB()->data_length); + } else if (request->Data() && request->Size()) { FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, - request->data(), request->size()); + request->Data(), request->Size()); } else prdEntrys = 0; @@ -885,14 +885,14 @@ AHCIPort::ExecuteSataRequest(sata_request* request, bool isWrite) fCommandList->prdtl_flags_cfl = 0; fCommandList->cfl = 5; // 20 bytes, length in DWORDS - memcpy((char*)fCommandTable->cfis, request->fis(), 20); + memcpy((char*)fCommandTable->cfis, request->FIS(), 20); - fTestUnitReadyActive = request->is_test_unit_ready(); - if (request->is_atapi()) { + fTestUnitReadyActive = request->IsTestUnitReady(); + if (request->IsATAPI()) { // ATAPI PACKET is a 12 or 16 byte SCSI command memset((char*)fCommandTable->acmd, 0, 32); - memcpy((char*)fCommandTable->acmd, request->ccb()->cdb, - request->ccb()->cdb_length); + memcpy((char*)fCommandTable->acmd, request->CCB()->cdb, + request->CCB()->cdb_length); fCommandList->a = 1; } @@ -905,7 +905,7 @@ AHCIPort::ExecuteSataRequest(sata_request* request, bool isWrite) TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex); ResetPort(); FinishTransfer(); - request->abort(); + request->Abort(); return; } @@ -949,11 +949,11 @@ AHCIPort::ExecuteSataRequest(sata_request* request, bool isWrite) if (status == B_TIMED_OUT) { TRACE("ExecuteAtaRequest port %d: device timeout\n", fIndex); - request->abort(); + request->Abort(); return; } - request->finish(tfd, bytesTransfered); + request->Finish(tfd, bytesTransfered); } @@ -989,7 +989,7 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb* request) return; } - sreq->set_atapi_cmd(request->data_length); + sreq->SetATAPICommand(request->data_length); // uint8* data = (uint8*) sreq->ccb()->cdb; // for (int i = 0; i < 16; i += 8) { // TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); diff --git a/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp b/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp index 2fe8b21..9114978 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp @@ -25,7 +25,7 @@ sata_request::sata_request() } -sata_request::sata_request(scsi_ccb *ccb) +sata_request::sata_request(scsi_ccb* ccb) : fCcb(ccb), fIsATAPI(false), @@ -45,16 +45,16 @@ sata_request::~sata_request() void -sata_request::set_data(void *data, size_t dataSize) +sata_request::SetData(void* data, size_t dataSize) { - if (fCcb) panic("wrong usage"); - fData = data; - fDataSize = dataSize; + ASSERT(fCcb == NULL); + fData = data; + fDataSize = dataSize; } void -sata_request::set_ata_cmd(uint8 command) +sata_request::SetATACommand(uint8 command) { memset(fFis, 0, sizeof(fFis)); fFis[0] = FIS_TYPE_REGISTER_HOST_TO_DEVICE; @@ -65,9 +65,9 @@ sata_request::set_ata_cmd(uint8 command) void -sata_request::set_ata28_cmd(uint8 command, uint32 lba, uint8 sectorCount) +sata_request::SetATA28Command(uint8 command, uint32 lba, uint8 sectorCount) { - set_ata_cmd(command); + SetATACommand(command); fFis[4] = lba & 0xff; fFis[5] = (lba >> 8) & 0xff; fFis[6] = (lba >> 16) & 0xff; @@ -78,9 +78,9 @@ sata_request::set_ata28_cmd(uint8 command, uint32 lba, uint8 sectorCount) void -sata_request::set_ata48_cmd(uint8 command, uint64 lba, uint16 sectorCount) +sata_request::SetATA48Command(uint8 command, uint64 lba, uint16 sectorCount) { - set_ata_cmd(command); + SetATACommand(command); fFis[4] = lba & 0xff; fFis[5] = (lba >> 8) & 0xff; fFis[6] = (lba >> 16) & 0xff; @@ -103,10 +103,10 @@ sata_request::SetFeature(uint16 feature) void -sata_request::set_atapi_cmd(size_t transferLength) +sata_request::SetATAPICommand(size_t transferLength) { fIsATAPI = true; - set_ata_cmd(0xa0); + SetATACommand(0xa0); if (1 /* isPIO */) { if (transferLength == 0) transferLength = 2; @@ -119,13 +119,13 @@ sata_request::set_atapi_cmd(size_t transferLength) void -sata_request::finish(int tfd, size_t bytesTransfered) +sata_request::Finish(int tfd, size_t bytesTransfered) { - if (tfd & (ATA_ERR | ATA_DF)) { + if ((tfd & (ATA_ERR | ATA_DF)) != 0) { uint8 status = tfd & 0xff; uint8 error = (tfd >> 8) & 0xff; - if (!is_test_unit_ready()) { + if (!IsTestUnitReady()) { dprintf("ahci: sata_request::finish ATA command 0x%02x failed\n", fFis[2]); dprintf("ahci: sata_request::finish status 0x%02x, error 0x%02x\n", @@ -140,7 +140,7 @@ sata_request::finish(int tfd, size_t bytesTransfered) if (tfd & (ATA_ERR | ATA_DF)) { fCcb->subsys_status = SCSI_REQ_CMP_ERR; if (fIsATAPI) { - if (!is_test_unit_ready()) { + if (!IsTestUnitReady()) { dprintf("ahci: sata_request::finish ATAPI packet %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x (len %d)\n", @@ -181,10 +181,10 @@ sata_request::finish(int tfd, size_t bytesTransfered) void -sata_request::abort() +sata_request::Abort() { dprintf("ahci: sata_request::abort called for command 0x%02x\n", fFis[2]); - if (fCcb) { + if (fCcb != NULL) { fCcb->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(fCcb, 1); delete this; @@ -196,16 +196,16 @@ sata_request::abort() void -sata_request::wait_for_completion() +sata_request::WaitForCompletion() { - if (fCcb) panic("wrong usage"); + ASSERT(fCcb == NULL); acquire_sem(fCompletionSem); } int -sata_request::completion_status() +sata_request::CompletionStatus() { - if (fCcb) panic("wrong usage"); + ASSERT(fCcb == NULL); return fCompletionStatus; } diff --git a/src/add-ons/kernel/busses/scsi/ahci/sata_request.h b/src/add-ons/kernel/busses/scsi/ahci/sata_request.h index 61191be..5686530 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/sata_request.h +++ b/src/add-ons/kernel/busses/scsi/ahci/sata_request.h @@ -5,88 +5,91 @@ #ifndef _SATA_REQUEST_H #define _SATA_REQUEST_H + #include "ahci_defs.h" #include "scsi_cmds.h" -class sata_request -{ + +class sata_request { public: - sata_request(); - sata_request(scsi_ccb *ccb); - ~sata_request(); + sata_request(); + sata_request(scsi_ccb* ccb); + ~sata_request(); - void set_data(void *data, size_t dataSize); + void SetData(void* data, size_t dataSize); - void set_ata_cmd(uint8 command); - void set_ata28_cmd(uint8 command, uint32 lba, uint8 sectorCount); - void set_ata48_cmd(uint8 command, uint64 lba, uint16 sectorCount); - void SetFeature(uint16 feature); + void SetATACommand(uint8 command); + void SetATA28Command(uint8 command, uint32 lba, + uint8 sectorCount); + void SetATA48Command(uint8 command, uint64 lba, + uint16 sectorCount); + void SetFeature(uint16 feature); - void set_atapi_cmd(size_t transferLength); - bool is_atapi(); - bool is_test_unit_ready(); + void SetATAPICommand(size_t transferLength); + bool IsATAPI(); + bool IsTestUnitReady(); - scsi_ccb * ccb(); - const void * fis(); - void * data(); - int size(); - void finish(int tfd, size_t bytesTransfered); - void abort(); + scsi_ccb* CCB(); + const void* FIS(); + void* Data(); + int Size(); + void Finish(int tfd, size_t bytesTransfered); + void Abort(); - void wait_for_completion(); - int completion_status(); + void WaitForCompletion(); + int CompletionStatus(); private: - scsi_ccb * fCcb; - uint8 fFis[20]; - bool fIsATAPI; - sem_id fCompletionSem; - int fCompletionStatus; - void * fData; - size_t fDataSize; + scsi_ccb* fCcb; + uint8 fFis[20]; + bool fIsATAPI; + sem_id fCompletionSem; + int fCompletionStatus; + void* fData; + size_t fDataSize; }; [ *** diff truncated: 54 lines dropped *** ] ############################################################################ Commit: 547cd462f843df15db02ed0dd7a35528221b66bc URL: http://cgit.haiku-os.org/haiku/commit/?id=547cd46 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Sat Nov 2 23:18:57 2013 UTC trim: Added is_called_via_syscall() function. * And use it in get_trim_data_from_user(), formerly known as copy_*(). * This fixes differentiating between user and kernel buffers. ---------------------------------------------------------------------------- ############################################################################ Commit: e6bde50a074e8e2b2f917f2758efe0604463c24d URL: http://cgit.haiku-os.org/haiku/commit/?id=e6bde50 Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Sat Nov 2 23:27:40 2013 UTC scsi_periph: use synchronous command. * The call waited anyway, so there is no reason to make it async. ---------------------------------------------------------------------------- ############################################################################ Revision: hrev46325 Commit: 0c873619ce86975e9ed3c66e88ca4dc9ef303a82 URL: http://cgit.haiku-os.org/haiku/commit/?id=0c87361 Author: Axel Doerfler <axeld@xxxxxxxxxxxxxxxx> Date: Sun Nov 3 22:17:36 2013 UTC Committer: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Commit-Date: Thu Nov 7 18:06:35 2013 UTC ahci: Fixed missing endian conversion. * Spotted by Rene, thanks a lot! ----------------------------------------------------------------------------