* ata: added ATADevice::ReadCapacity16()
* ata: don't fail if lba_sector_count is null and lba48_sector_count is not * scsi_periph: if ReadCapacity() returns 0xffffffff, use ReadCapacity16() instead * scsi_disk: use a different computation in the struct geometry computation for bigger disks Tested successfully with a virtual 10TB hard drive. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39252 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -313,7 +313,7 @@ typedef struct scsi_page_usn {
|
||||
char psn[1]; // size according to page_length
|
||||
} _PACKED scsi_page_usn;
|
||||
|
||||
// READ CAPACITY
|
||||
// READ CAPACITY (10)
|
||||
|
||||
typedef struct scsi_cmd_read_capacity {
|
||||
uint8 opcode;
|
||||
@@ -336,6 +336,22 @@ typedef struct scsi_res_read_capacity {
|
||||
uint32 block_size; // in bytes
|
||||
} _PACKED scsi_res_read_capacity;
|
||||
|
||||
// READ CAPACITY (16)
|
||||
|
||||
typedef struct scsi_cmd_read_capacity_long {
|
||||
uint8 opcode;
|
||||
uint8 service_action;
|
||||
uint64 lba;
|
||||
uint32 alloc_length;
|
||||
uint8 relative_address;
|
||||
uint8 control;
|
||||
} _PACKED scsi_cmd_read_capacity_long;
|
||||
|
||||
typedef struct scsi_res_read_capacity_long {
|
||||
uint64 lba; // big endian
|
||||
uint32 block_size; // in bytes
|
||||
} _PACKED scsi_res_read_capacity_long;
|
||||
|
||||
|
||||
// READ (6), WRITE (6)
|
||||
|
||||
|
||||
@@ -182,6 +182,26 @@ ATADevice::ReadCapacity(ATARequest *request)
|
||||
uint32 lastBlock = fTotalSectors - 1;
|
||||
data.lba = B_HOST_TO_BENDIAN_INT32(lastBlock);
|
||||
TRACE("returning last block: %lu\n", B_BENDIAN_TO_HOST_INT32(data.lba));
|
||||
|
||||
copy_sg_data(ccb, 0, ccb->data_length, &data, sizeof(data), false);
|
||||
ccb->data_resid = MAX(ccb->data_length - sizeof(data), 0);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ATADevice::ReadCapacity16(ATARequest *request)
|
||||
{
|
||||
TRACE_FUNCTION("%p\n", request);
|
||||
|
||||
scsi_ccb *ccb = request->CCB();
|
||||
scsi_res_read_capacity_long data;
|
||||
data.block_size = B_HOST_TO_BENDIAN_INT32(fBlockSize);
|
||||
|
||||
uint64 lastBlock = fTotalSectors - 1;
|
||||
data.lba = (((uint64)B_HOST_TO_BENDIAN_INT32(lastBlock >> 32)) << 32)
|
||||
| B_HOST_TO_BENDIAN_INT32(lastBlock);
|
||||
TRACE("returning last block: %llu\n", data.lba);
|
||||
|
||||
copy_sg_data(ccb, 0, ccb->data_length, &data, sizeof(data), false);
|
||||
ccb->data_resid = MAX(ccb->data_length - sizeof(data), 0);
|
||||
@@ -251,6 +271,11 @@ ATADevice::ExecuteIO(ATARequest *request)
|
||||
case SCSI_OP_READ_CAPACITY:
|
||||
return ReadCapacity(request);
|
||||
|
||||
case SCSI_OP_SERVICE_ACTION_IN:
|
||||
if ((ccb->cdb[1] & 0x1f) == SCSI_SAI_READ_CAPACITY_16)
|
||||
return ReadCapacity16(request);
|
||||
break;
|
||||
|
||||
case SCSI_OP_SYNCHRONIZE_CACHE:
|
||||
// we ignore range and immediate bit, we always immediately
|
||||
// flush everything
|
||||
@@ -443,7 +468,8 @@ ATADevice::Configure()
|
||||
}
|
||||
}
|
||||
|
||||
if (!fInfoBlock.lba_supported || fInfoBlock.lba_sector_count == 0) {
|
||||
if (!fInfoBlock.lba_supported || (fInfoBlock.lba_sector_count == 0
|
||||
&& fInfoBlock.lba48_sector_count == 0)) {
|
||||
TRACE_ERROR("non-lba devices not supported\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@ public:
|
||||
status_t Eject(ATARequest *request);
|
||||
status_t Inquiry(ATARequest *request);
|
||||
status_t ReadCapacity(ATARequest *request);
|
||||
status_t ReadCapacity16(ATARequest *request);
|
||||
virtual status_t ExecuteIO(ATARequest *request);
|
||||
|
||||
void GetRestrictions(bool *noAutoSense,
|
||||
|
||||
@@ -92,9 +92,16 @@ get_geometry(das_handle* handle, device_geometry* geometry)
|
||||
return status;
|
||||
|
||||
geometry->bytes_per_sector = info->block_size;
|
||||
geometry->sectors_per_track = 1;
|
||||
geometry->cylinder_count = info->capacity;
|
||||
geometry->head_count = 1;
|
||||
if (info->capacity > UINT_MAX) {
|
||||
// TODO this doesn't work for capacity greater than 35TB
|
||||
geometry->sectors_per_track = 256;
|
||||
geometry->cylinder_count = info->capacity / (256 * 32);
|
||||
geometry->head_count = 32;
|
||||
} else {
|
||||
geometry->sectors_per_track = 1;
|
||||
geometry->cylinder_count = info->capacity;
|
||||
geometry->head_count = 1;
|
||||
}
|
||||
geometry->device_type = B_DISK;
|
||||
geometry->removable = info->removable;
|
||||
|
||||
@@ -323,7 +330,7 @@ das_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
|
||||
das_handle* handle = (das_handle*)cookie;
|
||||
das_driver_info* info = handle->info;
|
||||
|
||||
TRACE("ioctl(op = %d)\n", op);
|
||||
TRACE("ioctl(op = %ld)\n", op);
|
||||
|
||||
switch (op) {
|
||||
case B_GET_DEVICE_SIZE:
|
||||
@@ -398,7 +405,7 @@ static void
|
||||
das_set_capacity(das_driver_info* info, uint64 capacity, uint32 blockSize)
|
||||
{
|
||||
TRACE("das_set_capacity(device = %p, capacity = %Ld, blockSize = %ld)\n",
|
||||
device, capacity, blockSize);
|
||||
info, capacity, blockSize);
|
||||
|
||||
// get log2, if possible
|
||||
uint32 blockShift = log2(blockSize);
|
||||
|
||||
@@ -56,6 +56,33 @@ periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *request)
|
||||
if (res == B_OK && request->data_resid == 0) {
|
||||
capacity = B_BENDIAN_TO_HOST_INT32(capacityResult.lba);
|
||||
|
||||
if (capacity == UINT_MAX) {
|
||||
RELEASE_BEN(&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);
|
||||
request->cdb_length = sizeof(scsi_cmd_read_capacity_long);
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->opcode = SCSI_OP_SERVICE_ACTION_IN;
|
||||
cmd->service_action = SCSI_SAI_READ_CAPACITY_16;
|
||||
|
||||
res = periph_safe_exec(device, request);
|
||||
|
||||
ACQUIRE_BEN(&device->mutex);
|
||||
|
||||
if (res == B_OK && request->data_resid == 0) {
|
||||
capacity = (((uint64)B_BENDIAN_TO_HOST_INT32(
|
||||
capacityLongResult.lba >> 32)) << 32)
|
||||
| B_BENDIAN_TO_HOST_INT32(capacityLongResult.lba);
|
||||
} else
|
||||
capacity = 0;
|
||||
}
|
||||
|
||||
// the command returns the index of the _last_ block,
|
||||
// i.e. the size is one larger
|
||||
++capacity;
|
||||
@@ -66,7 +93,7 @@ periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *request)
|
||||
blockSize = 0;
|
||||
}
|
||||
|
||||
SHOW_FLOW(3, "capacity = %Ld, block_size = %ld", capacity, blockSize);
|
||||
SHOW_FLOW(3, "capacity = %lld, block_size = %ld", capacity, blockSize);
|
||||
|
||||
device->block_size = blockSize;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user