Improve SCSI and SATA trim support

Fixes:
* scsi: Fix a bug that caused the device capacity to be set
  to an undefined value for some large SCSI devices when
  READ CAPACITY (16) was used
* ahci: Fix VPD page reporting so that it does not return
  undefined values
* ahci: Set the write bit to true when sending a DATA SET
  MANAGEMENT (trim) command to a device. The command would
  otherwise fail and time out on some devices.

Improvements:
* scsi: Extend the READ CAPACITY (16) support to also
  include logical block provisioning information
* scsi: Prefer READ CAPACITY (16) over READ CAPACITY (10)
  on devices that are expected to support this command
* scsi, ahci: Enable trim on SCSI and SATA devices that
  are expected to support trim and which correctly report
  trim support
* ahci: Redo the implementation of the SCSI UNMAP command
* scsi: Redo UNMAP-related code
* scsi: Add support for UNMAP via WRITE SAME (10) and
  WRITE SAME (16) commands
* When copying trim ranges between different data types,
  make sure that the values don't change (detect overflows)
* Report the number of trimmed blocks even if the trim
  operation fails

Change-Id: Ie5fc993bbbc19546b4308138ba10184bf7b9986a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4157
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
David Sebek
2021-07-16 18:35:57 +00:00
committed by Adrien Destugues
parent bd02d81c24
commit 8b1d35bdbb
11 changed files with 1133 additions and 272 deletions
+53 -5
View File
@@ -255,7 +255,10 @@ typedef struct scsi_res_inquiry {
// Asynchronous Event Notification Capable
);
uint8 additional_length; // total (whished) length = this + 4
uint8 _res5;
B_LBITFIELD8_2(
protect : 1,
_res5_1 : 7
);
uint8 _res6;
B_LBITFIELD8_8(
soft_reset : 1, // 0 = soft reset leads to hard reset
@@ -350,7 +353,7 @@ typedef struct scsi_page_block_limits {
);
uint8 page_code;
uint16 _page_length;
uint16 page_length;
B_LBITFIELD8_2(
wsnz : 1,
_res4_1 : 7
@@ -424,13 +427,36 @@ typedef struct scsi_cmd_read_capacity_long {
uint8 service_action;
uint64 lba;
uint32 alloc_length;
uint8 relative_address;
B_LBITFIELD8_2(
pmi : 1,
_res14_1 : 7
);
uint8 control;
} _PACKED scsi_cmd_read_capacity_long;
typedef struct scsi_res_read_capacity_long {
uint64 lba; // big endian
uint32 block_size; // in bytes
B_LBITFIELD8_4(
prot_en : 1,
p_type : 3,
rc_basis : 2,
_res12_6 : 2
);
B_LBITFIELD8_2(
logical_blocks_per_physical_block_exponent : 4,
p_i_exponent : 4
);
B_LBITFIELD8_3(
lowest_aligned_lba_p1 : 6,
// first part of the Lowest Aligned LBA field
lbprz : 1,
lbpme : 1
);
uint8 lowest_aligned_lba_p2;
// second part of the Lowest Aligned LBA field
// (B_LBITFIELD16_3 would not help here because of its alignment)
uint8 _res16[16];
} _PACKED scsi_res_read_capacity_long;
@@ -508,16 +534,38 @@ typedef struct scsi_cmd_rw_16 {
} _PACKED scsi_cmd_rw_16;
// WRITE SAME (10)
typedef struct scsi_cmd_wsame_10 {
uint8 opcode;
B_LBITFIELD8_6(
_obsolete1_0 : 1,
_obsolete1_1 : 1,
_obsolete1_2 : 1,
unmap : 1,
anchor : 1,
write_protect : 3
);
uint32 lba;
B_LBITFIELD8_2(
group_number : 5,
_res6_5 : 3
);
uint16 length;
uint8 control;
} _PACKED scsi_cmd_wsame_10;
// WRITE SAME (16)
typedef struct scsi_cmd_wsame_16 {
uint8 opcode;
B_LBITFIELD8_6(
_res1_0 : 1,
ndob : 1,
lb_data : 1,
pb_data : 1,
unmap : 1,
_res1_4 : 1,
anchor : 1,
write_protect : 3
);
uint64 lba;
+3 -2
View File
@@ -73,7 +73,8 @@ typedef struct scsi_periph_callbacks {
} scsi_periph_callbacks;
typedef struct scsi_block_range {
uint64 offset;
// values are in blocks
uint64 lba;
uint64 size;
} scsi_block_range;
@@ -123,7 +124,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,
scsi_block_range* ranges, uint32 rangeCount);
scsi_block_range* ranges, uint32 rangeCount, uint64* trimmedBlocks);
// *** removable media ***
// to be called when a medium change is detected to block subsequent commands